BorisMoore / jsviews

Interactive data-driven views, MVVM and MVP, built on top of JsRender templates
http://www.jsviews.com/#jsviews
MIT License
856 stars 130 forks source link

Regression Breaking my Nested jQuery Plugins #405

Closed nfplee closed 6 years ago

nfplee commented 6 years ago

The latest version has a problem wiring up my nested jQuery plugins. It's probably best to illustrate with an example. See the following for a working example using an older version of JsViews:

http://jsfiddle.net/30zocn69/

If you click on "Edit" next to either of the names then the inner list is wired-up correctly. The inner list is wired up because as you switch between the item and edit templates it triggers the "contentUpdated" event against the element. I then subscribe to this event and wire up the list the same way I do on the document ready but only within the updated HTML.

I use this approach for all my jQuery plugins and always trigger the contentUpdated event against any updated HTML. This means my plugins are wired up for any dynamically updated content.

However with this latest version this example doesn't appear to be working. See below for an example which has the same code but uses the latest version of JsViews:

https://jsfiddle.net/ogk1wzpc/

Notice as you click on "Edit" the nested list does not show.

I'd appreciate it if you could help. Thanks

BorisMoore commented 6 years ago

It looks like the issue is from a change introduced in commit 59:

See https://github.com/BorisMoore/jsviews/issues/279.

You can no longer use top-level data-linking link(true, ...) on content that is part of a rendered template, since that content will already have data-link bindings for observable changes, so allowing setting of new bindings through top-level linking will lead potentially to conflicts/unpredictable behavior, memory leaks etc. - depending on the firing sequence of old and new observable update handlers.

If you change this line https://github.com/BorisMoore/jsviews/blob/master/jsviews.js#L4508 to } else if (tmplOrLinkExpr === true ) { your sample works. But I don't recommend it.

You should be able to use regular template linking with toggling editable mode to replace your current top-level linking approach. (As in this sample http://www.jsviews.com/#samples/tag-controls/tree/editable). But the way you mix the data into the view (your data-model idea) may make it more tricky.

nfplee commented 6 years ago

Thanks Boris, I think I'll accept the slight hack for now otherwise I have a lot of work to do converting my plugins to use tags.

BorisMoore commented 6 years ago

Here is an alternative approach to your scenario: https://jsfiddle.net/BorisMoore/yg6nmngr/1/

Note that it uses Top-level programmatic data-linking rather than the top-level declarative data-linking you used. By creating a custom tag you take advantage of the life-cycle (onBind) to deal with having to wait until after data-linking to get the data-model data.

BTW your fiddle used jquery-1.9.1 - but that version is deprecated and there is a bug which will break my sample fiddle above. Better to use jquery-3.x.

nfplee commented 6 years ago

Thanks again. I think I follow your sample.

The thing I've never liked/understood is what the hat adds to {^{...}}. I've always used {{...}} as I find it much cleaner and it's always worked fine for my needs. If the hat simply adds additional data linking benefits then why not drop the hat and make it the default?

BorisMoore commented 6 years ago

http://www.jsviews.com/#linked-tag-syntax

Sometimes you don't want a tag to have active data-link bindings. Without the ^ it is simply rendered. If you have a lot of instances of the tag, you can have a performance gain by not data-linking. (Especially for disposal, when the HTML is removed.)

Also you use un-linked tags within attribute markup: <input ... title="{{:title}}"/>. Doing <input ... title="{^{:title}}"/> is not allowed.