Knockout.js - Change other observables in viewmodel from extender or other way to do something similar

StackOverflow https://stackoverflow.com/questions/23427569

  •  14-07-2023
  •  | 
  •  

Pregunta

I've been doing some simple knockout things before, but this one feels a more complicated. A client wishes to be able to control the number of order rows in a form with the help of a dropdown (I asked why they didn't want a regular add button, but they said this would give them better overview that everything was filled out...).

I have an observable holding the value from the dropdown and an observableArray to hold the order rows, but I had to confirm the selection was intended when the new value is less than the previous.

So I started scouring the internet for tips and tricks how to accomplish this. First I found this "confirmable" extender. It helped me show a confirm dialog if the number of rows they selected was less than the previous value, but I found no way to interact with other observables in the viewmodel from it.

So I Google'd some more and found the first answer from Michael Best here. With the "subscribeChanged" function I could now (after the confirmable extender did its part) add or remove rows to the observable array of order rows.

However. I would like for there to be some better way to accomplish this in order to not have the almost exact code in more than one place. Because now I have this code in the extender

if (!isValidateInteger(current) && isValidateInteger(newValue)) {
    target(newValue);
    // TODO: Add rows to vm.orderRows so the count reflects newValue
}

and this code in subscribeChanged function

if (!isValidateInteger(current) && isValidateInteger(newValue)) {
    // NOTE: Add rows to vm.orderRows so the count reflects newValue
    difference = (newValueInt - currentInt);
    message += '<br />Add ' + difference + ' row(s).';
    for (var i = 0; i < difference; i++) {
        vm.orderRows().push(new OrderRow());
    }
    vm.orderRows.valueHasMutated();
}

I've put together this fiddle with an excerpt of the code I have today.

I know some of the if-statements don't need to be there, but they're for debugging purpose at the moment. I will look at which to remove when the functionality is completed and tested, but any pointers (even ones not pertaining the question) are welcome.

Thanks in advance, Ludvig

¿Fue útil?

Solución

You can use a computed observable to both use confirm and update if ok:

vm.enhancedNumberOfOrderRows = ko.computed({
    read: vm.numberOfOrderRows,
    write: function(newValue) {
        //do all your checks, update vm.numberOfOrderRows only if you want
    }
});

See the exemple: http://jsfiddle.net/v3EAz/2/

EDIT: You have to call vm.numberOfOrderRows.valueHasMutated(); if user canceled to update the value of the select.

See: http://jsfiddle.net/v3EAz/3/

Otros consejos

An extender may not be the best fit for your scenario. Seems like it's making you jump through unnecessary hoops and the extender logic is specific to your viewmodel/screen, it's not a generic extender that could be reused in other situations.

A simpler approach might be to use the knockout observable's subscribe function to listen for changes to numberOfOrderRows and react accordingly.

var vm = {
    numberOfOrderRows: ko.observable(''),
    orderRows: ko.observableArray(),
};

vm.numberOfOrderRows.subscribe(
... todo write a numberOfOrderRowsChanged handler function to do the following:
1) validate the new value
2) perform any user confirmation logic
3) if successful, update the orderRows observable
4) if unsuccessful, restore the previous value to numberOfOrderRows
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top