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

Strip out trailing line feed and space on html generated by Js View #379

Closed longgt closed 7 years ago

longgt commented 7 years ago

I'm creating table with dynamic data binding by Js View.

Template

<table>
  {^{for rows}}
    <tr>
     {^{for cols}}
       <td>{>{name}}
          <span class="icon">
            <img src="setting.png">
            <img src="remove.png">
          </span>
      </td>
    {{/for}}
   </tr>
  {{/for}}
</table>

Data

var list = {
  rows: [
    {
      cols: [
         {
           "name": "John"
         }
      ]
    }
  ]
}

Source

var myTmpl = $.templates("#tableTmpl");
myTmpl.link("#personList", list);

When I run code above, the output html is below

<table>
  <tr>
     <td>John
          <span class="icon">
            <img src="setting.png">
            <img src="remove.png">
          </span>
      </td>
  </tr>
</table>

But if I display the output above in JSF 2.0, trailing space is displayed between setting icon and remove icon. It can be resolved by doing a trick by removing all line feed and trailing space as following:

<table><tr><td>John<span class="icon"><img src="setting.png"><img src="remove.png"></span></td></tr></table>

So my question is "How can I inject my handler for output html rendered by Js View before rendering?" So I can modify output html and pass it back to JsView render engine.

Since the code above updated by changing data by Js Observable, I can't simply get html of #personList, modify it and put it back (After modified, when I changed data by Js Observable, table will not be rendered again)

Here is my code for changing data

var modifiedRows = list.rows.slice();
//Modify data in rows: add column, delete column, add row, delete row, merge cell..etc
$.observable(list).setProperty("rows", modifiedRows );

P/S: For maintenance, I don't want to strip out line feed and space in template because readability of source code.

BorisMoore commented 7 years ago

JsViews and JsRender are designed to faithfully render whatever markup you put in the template. There are many scenarios in which the template is rendered. Your scenario would require overriding all those scenarios.

JsViews is based on data-driven rendering using declarative templates. There are a few event handlers available, and advanced approaches like creating a custom {{for}} tag in which you override the render method. But it would be tricky to achieve your scenario, and, more importantly, quite risky as far as maintainability is concerned.

My recommendation is either to use data-driven UI, with templates, or use code to manipulate the DOM directly. But don't mix the two in complex ways if you want reliability and maintainability. I would suggest that fidelity of templates is more important than readability. Create a build system with two versions of each template, if you want, one "pretty" and the other "as rendered".

eugene-panferov commented 7 years ago

i must confess. i am watching this list ever since i started using jsViews. i totally fail to understand what is the nature of the problems that people are posting here (if i was to find any bug that they occasionally post i would fail too).

I have completed a pretty much sophisticated UI (a board game) with only the basic facilities of jsViews, and it simply works. I am failing to imagine a task that will REQUIRE to redefine {{for}} or something of similar magnitude.

Thanx.

longgt commented 7 years ago

I'll try to manipulate DOM directly. Thanks Boris for your answer.

BorisMoore commented 7 years ago

OK - but maybe you misunderstood me. If you are using JsViews, I discourage trying to manipulate the DOM (if as a result it does not correspond to the template). Keep the DOM faithful to the template if you want maintainability.

longgt commented 7 years ago

Sorry, I'll explain more... I intended to get template content in readable form, strip out trailing line feed by DOM manipulate and use result as template for Js View. I just inject my handler before compiling template, not rendering.

BorisMoore commented 7 years ago

Ok - yes that sounds better. :)