1
votes

I'm having an issue with a JSViews template updating when the underlying data changes. It involves a span that is data-linked using a converter function to the underlying data. When the underlying data changes after an async call back to the server, the span text is not updating.

Markup:

{^{for thedata.myarrayobject}}
    <span data-link="{myconverter:var1:} name{:'theName' + var2}"></span>
{{/for}}

Script:

$.views.converters({
    myconverter: function (val) {
        switch (val) {
            case 1: 
                return 'Test1'; 
                break;
            case 2: 
                return 'Test2';
                break;
            default: 
                return 'Default';
        }
    }
});

The span correctly displays on page load based on the values in thedata.myarrayobject. E.g. if we have:

thedata.myarrayobject[0].var1='1';
thedata.myarrayobject[0].var2='John';
thedata.myarrayobject[1].var1='2';
thedata.myarrayobject[1].var2='Matthew';

it will load as:

<span name="theNameJohn">Test1</span>
<span name="theNameMatthew">Test2</span>

However, if the underlying data changes after an async callback to:

thedata.myarrayobject[0].var1='2';
thedata.myarrayobject[0].var2='John';
thedata.myarrayobject[1].var1='1';
thedata.myarrayobject[1].var2='Matthew';

the span text is just staying the same.

I have debugged the js code and the underlying array parameter 'var1' is definitely being set to the new value. I have tried calling:

$.observable(thedata.myarrayobject).refresh(thedata.myarrayobject);

but to no avail.

I obviously want the span text to adjust as the underlying data changes - any help would be greatly appreciated!

2
Can you show your code for how your are initially linking to the data, and then your code for updating to the new data. Ideally a jsfiddle - with a button calling your current code for updating to the new data? Then I'll take a look...BorisMoore
Hi @BorisMoore - jut to answer your question, I am using the link() method so the data-links should work.... but your second question about how I update the data has pointed me in the right direction. I'm doing it as above: just directly updating the parameter values in js. I;ve just tried it in an observable wrapper - and it has worked! I'll post it below. Is there any way I can give you some credit for this - I doubt I would have done it without your comment!Marco
I added an answer to show some of the alternative ways you can merge data 'observably'.BorisMoore

2 Answers

2
votes

In fact to make an update, you need to choose your own strategy for merging the new data (e.g. from an Ajax call) with the previous data.

But any merge must be done using the 'observable' APIs - so that JsViews receives the data-linking update notifications and updates your UI.

So depending on your data and scenario, you could use any of the following kinds of update:

  1. Change the leaf values one at a time:

    $.observable(thedata.myarrayobject[0]).setProperty("var1", "2");

  2. Change the leaf values one object at a time:

    $.observable(thedata.myarrayobject[0]).setProperty(newarrayobject[0]);

    (This will pick up any modified properties)

  3. Refresh the whole array with the new objects:

    $.observable(thedata.myarrayobject).refresh(newarrayobject);

    (This will copy the new objects/items over into the myarrayobject)

  4. Update the myarrayobject with the new one:

    $.observable(thedata).setProperty("myarrayobject", newarrayobject);

    So here you are replacing the array with a new one...

Any or each of the above will trigger updates with the new data values.

Note that the above methods assume you have downloaded a new data array, newarrayobject which contains updated data to merge into your previous myarrayobject. You don't need to clone either the newarrayobject or the previous myarrayobject.

1
votes

Well after BorisMoore above asked a couple of questions... The way I was updating the data - just pushing it direct into the array parameters as above:

thedata.myarrayobject[0].var1='2';
thedata.myarrayobject[0].var2='John';
thedata.myarrayobject[1].var1='1';
thedata.myarrayobject[1].var2='Matthew';

was not working, and my call to $.observable(...).refresh(...) did not work because I was passing the same array: no changes were triggered to update to the markup.

Simply, I copied the array to a new one, updated the values, then called refresh, which works:

var myduparrayobject = thedata.myarrayobject.splice();

myduparrayobject [0].var1='2';
myduparrayobject [0].var2='John';
myduparrayobject [1].var1='1';
myduparrayobject [1].var2='Matthew';

$.observable(thedata.myarrayobject).refresh(myduparrayobject);

The problems:

  1. Only observable changes to the array will be refreshed to the markup. Not just simply updating the object data as I thought it did.

  2. $.observable(...).refresh(...) only works when a changed array to the referenced object is passed in. Passing the same referenced object like I did (even if it differs from what is being displayed in the markup) will not trigger changes to the template markup.