How to update/filter the underlying observable value using a custom binding?
Asked Answered
G

1

0

Problem

I have created a custom binding that replaces html br occurences in an observable with \r\n in order to be displayed in a textarea. This works OK for the initial display of the value, but furthers changes to the displayed text don't trigger the update function of the custom binding.

Code

ko.bindingHandlers.Br2Nl = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {     
        var observable = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(observable);
        var transformed = Br2Nl(valueUnwrapped);
        $(element).val(transformed);
    }
};
function Br2Nl(content)
{
    var response = new String(content);
    return response.replace(/<br \/>/g, "\r\n");
}

My initial assumption was that the problem was that I didn't actually trigger the update of the underlying observable so I modified the update function to do so, but with no success:

update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {     
        var observable = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(observable);
        var transformed = Br2Nl(valueUnwrapped);
        //update observable with transformed value
        observable(transformed);
        $(element).val(transformed);
    }

Is there a proper way to update/filter the value of an observable using a custom binding?

Custom binding usage:

<textarea data-bind="Br2Nl: PropertyName" rows="5">  </textarea>

This is the fiddle for it: http://jsfiddle.net/bWHBU/

As it can be observed, nothing happens to the observable(div below) when the content of the textarea changes. However, when the 'Br2Nl' custom binding is replaced with the 'value' binding, the observable is updated.

Final solution here: http://jsfiddle.net/bWHBU/5/

Replaced 'keyup' with 'change' event to avoid vertical scrollbar repositioning issue on Firefox.

Gavrilla answered 27/3, 2013 at 10:37 Comment(8)
Where does the value change initially?Chism
@PaulManzotti The value is initialiazed from an AJAX responseGavrilla
Yeah, but how do you change the value? Is it another ajax call? How are you updating the value in the view model?Chism
@PaulManzotti That's what I was referring to. An ajax call that pulls an object from the server and updates its coresponding model in JS. Ex: ViewModel.Property(ObjectModel.Property);Gavrilla
What I mean is that the custom binding update method will only fire when you update the observable property that it is bound to. Can you show the code for that. What you have in your question looks fine to me, so it's probably a problem in another part of your code.Chism
@PaulManzotti added custom binding usage in html. Nothing special there, it has been used for some time across a fairly big application with no issues so far.Gavrilla
You're still missing my point. Can you show us the code that updates this observable property during the lifetime of the page? So far, you've said that it is initialised from an AJAX call, and also updated by an update call. Can you put the code for that into your question please?Chism
@PaulManzotti The code that updates this observable property is part of a generic JS service that updates all models from all view models and I didn't include because I don't think it's an issue in this context and will add unnecessary complexity to the question. As I said, the initial value is loaded and displayed correctly and after that the changes to the observable are done only via the textarea html control.Gavrilla
C
2

You have not instructed knockout when to update the observable property when the text in the text area changes. Try this:

ko.bindingHandlers.Br2Nl = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        ko.utils.registerEventHandler(element, "keyup", function() {
            var observable = valueAccessor();
            var valueUnwrapped = ko.utils.unwrapObservable(observable);    
            var transformed = Br2Nl($(element).val());
            observable(transformed);
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {     
        var observable = valueAccessor();
        var valueUnwrapped = ko.utils.unwrapObservable(observable);
        var transformed = Br2Nl(valueUnwrapped);
        $(element).val(transformed);
    }
};

It might take a bit of tinkering to get the keyup method correct, but that should be a good start.

Updated your jsFiddle. You were referencing raw.github for the mapping plugin, and browsers can't parse files from there correctly. Added a usable external reference.

Chism answered 27/3, 2013 at 12:36 Comment(2)
Created a jsFiddle for it here: jsfiddle.net/bWHBU/1. The problem is that now the initial observable value is not displayed in the textarea.Gavrilla
Thanks. However, when I change the content of the textarea the view model property still doesn't get updated. I'll try to figure it out...Gavrilla

© 2022 - 2024 — McMap. All rights reserved.