chaplinjs / chaplin

HTML5 application architecture using Backbone.js
http://chaplinjs.org
Other
2.85k stars 231 forks source link

Rerender of noWrap view doesn't work the way expected #731

Open codepunkt opened 10 years ago

codepunkt commented 10 years ago
class SomeView extends View
  noWrap: true
  template: template
  listen:
    'change model': 'render'

I'd expect the view in the DOM to be updated with the new information from the model - e.g. the same way this works in the TodoMVC Chaplin-App.

Due to this view being configured with noWrap: true, a call to render only changes the @el and @$el properties of the view instance, but neither removes the old @el from the DOM nor inserts/appends the new one.

Im trying to figure out how this should properly be done. How can i simply rerender a noWrap view on changes?

karellm commented 10 years ago

I have the problem too. Every render populates the container with a new version of the html.

In Chaplin.View, why do you need to do this when the noWrap option is set:

# Undelegate the container events that were setup.
@undelegateEvents()
# Delegate events to the top-level container in the template.
@setElement el.firstChild, true

Shouldn't the element stay the same?

ghost commented 10 years ago

The current implementation wraps html returned by the templating function in a div then pulls it out. I believe the correct approach for View#render would be to use the template element and look something like this:

if @noWrap
  template = document.createElement 'template'
  template.innerHTML = html
  fragment = template.content

  if fragment.children.length > 1
    throw new Error 'There must be a single top-level element when ' +
                    'using `noWrap`.'

  # Undelegate the container events that were setup.
  @undelegateEvents()
  # Delegate events to the top-level container in the template.
  @setElement fragment, true
else
  setHTML (if $ then @$el else @el), html

Notice how the above avoids the whole wrapping concept altogether. I believe that's the key.

However, the template element, despite being a WC3 Established Standard and WebPlatform initiative, is not supported by IE11 or below though official support of the template element is under consideration for a future version of IE.

Another approach would be to use of the kind of lame document.createDocumentFragment method to construct DOM nodes programmatically, but that approach would be flimsy and prone to error IMO.

sheinzle commented 9 years ago

I would love to see a fix for this. Currently, we have the following workaround using jQuery's replaceWith function:

class BaseView extends Chaplin.View
  # noWrap bugfix for re-rendering
  render: ->
    elBefore = @$el
    super
    if @noWrap && elBefore? && !elBefore.is(document.body) && !elBefore.is(@$el)
      elBefore.replaceWith @$el

This only works in projects with jQuery. CollectionView needs to be extended the same way. Code might have some issues.