I built this rudimentary tool for creating a Menu where multiple/identical Source items may be attached (1 to many). This isn't really a merge, because I need Source items to be editable and data bound to all it's instances in the Menu. This involves two arrays: one the Source and the other for Menu where a common ID connects the items and ID's for their sub-items. Menu includes inputs for override/customization.
The problem I am having is with refreshing the data when changes are made. I've had to resort to using $.templates("#myTmpl").link("#renderMenu", data)
into two different places as data is changed.
This is not ideal as it re-renders everything; although in my case everything in two-way data bound, so no loss.
view.refresh()
does not work either
I think the problem is because itemVar
does not get updated when it's underlying data is changed...itemVar
is for single pass rendering from what I understand.
I also tried helpers in place of itemVar
like ^~items=myItems
...they didn't work either.
So the question is how to trigger refreshing on certain view's/parts without resorting to: <$.templates("#myTmpl").link("#renderMenu", data)>
To test:
$.templates("#menuTmpl").link("#renderMenu", data)
itemVar="~currentItem"
on line 8, where itemVar does not get updated nor trigger a refresh. The underlying data is changed however.Perhaps there is a better way of building this tool or parts of it; as it includes a bit of trickery (filter ... step=100
) and probably unnecessary 'for' looping.
I'll admit...it took me 5 versions to build as it was very tricky getting all things working together.
Any pointers would be much appreciated.
Fiddle showing the problems: https://jsfiddle.net/alnico/mt5d2v7j/
There are ID's on all rendered items for debugging.
You are right about itemVar
not updating - in the sense that if a new array item is added, the view for that item does not have an itemVar
contextual parameter (such as ~currentItem
in your sample). I will fix that in the next update. I created an issue here https://github.com/BorisMoore/jsviews/issues/424, and you can test it out with the updated jsviews.js file you will find there.
The other immediate issue you have is that you have:
{^{for ~root[1].allItems filter=~menuItem id=id}}
But the menuItem
filter depends on the id
, so it needs to be refreshed whenever id
changes. You can achieve that either by declaring the dependency on the menuItem function:
$.views.helpers.menuItem.depends = "id";
or by using mapDepends:
{^{for ~root[1].allItems filter=~menuItem id=id mapDepends='id'}}
You can simplify things a bit by removing the id=id
and writing
menuItem: function(item, index, items) {
return item.id == this.view.data.id;
}
Or better, don't use a filter on the {{for}}
, but simply use a helper function to return the filtered items directly:
getItem: function(id) {
return data[1].allItems.filter(function(item) {
return item.id == id;
});
}
used like this:
{^{:#index}}
{^{for ~getItem(id)}}
{^{if ~currentItem.isNewItem != '1'}}
If you do that you no longer need to use mapDepends or .depends on your filter function. Changes in id
will trigger a refresh of {^{for ~getItem(id)}}