Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force knockout to mark an observable as changed (even if focus is still in the field)

I develop a project with knockout/breeze.

I would like to know if it is possible to force knockout to mark an observable as changed (even if focus is still in the field). My goad is to notify user that whenever he begin to change the date he has the ability to save it (with a button showed immediately). For example, I have an input field with dates. User begin to edit the date in this field. The observable should only interpret the new encoded date when user leave focus of the field. But I would like to show my Save button as soon as he begin to type something in the input field. I hope I'm clear.

Here is my bindingHandlers for taking care of editing dates in my input:

ko.bindingHandlers.dateRW = {
    //dateRW --> the 'read-write' version used both for displaying & updating dates
    init: function (element, valueAccessor, allBindingsAccessor) {
        var observable = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor);
        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {                
            var myDate = moment($(element).val(), "DD/MM/YYYY");
            observable(myDate.toDate());
        });
        //ko.utils.registerEventHandler(element, "keyup", function () {
        //    As soon as user begin to type something, I would like to show my save button
        //});
    },
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var date = (typeof value !== 'undefined') ? moment(value) : null;
        var dateFormatted = (date != null) ? date.format('DD/MM/YYYY') : '';
        $(element).val(dateFormatted);
    }
};

And my view:

<input type="text" data-bind="dateRW: myDate" />

Unfortunately valueUpdate: 'afterkeydown' does not work because I'm using a custom bindingHandlers.

Hope someone could point me in the right direction.

Thanks.

like image 500
Bronzato Avatar asked Apr 28 '13 09:04

Bronzato


People also ask

How do I set observable value in knockout?

To create an observable, assign the ko. observable function to the variable. A default value can be specified in the constructor of the call. Knockout then converts your variable into a function and tracks when the value changes, in order to notify the UI elements associated with the variable.

What is Ko observable ()?

An observable is useful in various scenarios where we are displaying or editing multiple values and require repeated sections of the UI to appear and disappear as items are inserted and deleted. The main advantage of KO is that it updates our UI automatically when the view model changes.

How do we activate a knockout model?

To activate Knockout, add the following line to a <script> block: ko. applyBindings(myViewModel); You can either put the script block at the bottom of your HTML document, or you can put it at the top and wrap the contents in a DOM-ready handler such as jQuery's $ function.


1 Answers

Try observable.valueHasMutated()

EDIT In other comments you mentioned that you are binding your save enabled to 'context.hasChanges()' (which is updated from a Breeze EntityManager?).

I believe Breeze doesn't update hasChanges by subscribing to Knockout observable notifications. I think it actually wraps the observable setting function and also checks to make sure that the value is actually changing. In other words I believe you would actually have to change your observables value (and then back) to trigger hasChanges().

Another (not so good) option might be to try and get back to the observable's parent object and get it's EntityAspect. You could then call `setModified()'. Doing all this in a binding handler does seem like a bad idea as it really starts to assume the observable you are binding to is a property on a Breeze entity.

You may be best (no pun intended) to consider an option similar to Michael's answer. Perhaps create a saveEnabled() observable in your viewmodel like:

var saveEnabled = ko.observable(false);
context.hasChanges.subscribe(function() { saveEnabled(true); });

You could then either use the keyup binding that Michael suggests or add another subscribe above on your date observable - and go back to calling valueHasMutated() in the binding handler (if you can find it) .

like image 195
Brendan Avatar answered Nov 15 '22 09:11

Brendan