Reassign Backbone View to a newly created DOM element

I am creating a search results page using Backbone in combination with CoffeeScript and Handlebars. I have two types: one for the list of results (ListView), and the second for one result (ResultView). Simplified code:

ListView = Backbone.View.extend el: $("ul#results") ... addItem: (result) -> resultView = new ResultView({ model: result }) resultView.parentView = this this.el.append(resultView.render().el) ResultView = Backbone.View.extend tagName: "li" className: "result" events: ... 

Brief explanation:

  • ListView assigned to ul#results
  • When the result is added to the listview, a ResultView is created, which has the knowledge of its parent and makes it itself
  • An element li.result is created for li.result (default behavior by default)

This is the (simplified) template that I use to render the search result:

 <li class="result"> <h1> <a href="{{link}}">{{title}}</a> </h1> <p>{{snippet}}</p> </li> 

Here is my mystery, as you may have found yourself: I define li.result in my Backbone ResultView and in my template. What I can not do:

  • Bind ResultView to li.result in my template because it does not exist in the DOM yet
  • Remove li.result from my template because I still need it to display the page page server for those who don't have JavaScript.

Is there a way (elegantly) to reassign the Backbone view for an element after it is created? Or simply, can I refer to the ResultView on a temporary element, render the template and then move it to ul#result ? Or am I looking at it wrong?

Thanks!

+4
source share
2 answers

I would suggest just calling the displayed event from your view and then doing your operations in the onRendered callback like this:

 initialize: function() { this.bind('rendered', onRendered); }, onRendered: function() { // do onRendered stuff // eg. remove an element from the template }, render: function() { // your render stuff this.trigger('rendered'); } 
+2
source

I found that everything will get complicated when you try to support server-side views and client-side views. The script you are describing here is a great example of this.

If at all possible, I would move the page rendering to the client side, which would greatly simplify your code.

If you want to save views processed by the server, I would probably execute the fetch () function in your collection after loading the page to get all objects from the server. You can then configure the ResultView initialization function to perform the following test.

 ResultView = Backbone.View.extend initialize: (attributes) -> exisitingElement = $('result_' + attributes['id']) if exisitingElement? @el = exisitingElement @delegateEvents() 

Then you change your template to a unique identifier.

  <li id="result_{{id}}" class="result"> <h1> <a href="{{link}}">{{title}}</a> </h1> <p>{{snippet}}</p> </li> 

Thus, ResultView will search for an existing item before rendering a new one to the page. Manually calling delegateEvents () after reassigning the @el property ensures that all events that you define will continue to work.

+1
source

Source: https://habr.com/ru/post/1386404/


All Articles