Build html in server and bind to ng-repeat - javascript

I have some table that ng-repeat is building. the table contains a lot of data, and sometimes the build phase of the html is taking 10-20 seconds on weak computers.
So i've started to explore about building the html in the server, but the problem is that i'll loose the data-binding, and i'm needing it because i have inline edit functionality in the table.
The ultimate solution will be rendering the table in the server-side, with all the directives remaining including the ng-repeat, and on the client, makes the ng-repeat recognize that the html already has been rendered for the first time and not render it again, until the first change in the data.
In the Angular source code in the ngRepeatDirective, there is the "lastBlockMap" object that contain mapping betwee each element created by ng-repeat, to his scope, in that structure :
clone: [THE_ELEMET]
id: "005"
scope: ChildScope
and from reading this arcticle :
http://www.bennadel.com/blog/2443-Rendering-DOM-Elements-With-ngRepeat-In-AngularJS.htm
i've got to conclusion that if i'll create this object, and pass it somehow to the ng-repaat directive, the directive will know that the html is already been rendered and will not render it again.
The problem is how to pass such information to ng-repeat???
Any one encountered this situation??
P.S.
I'm familiar with all the "ngRepeat preformance" posts and arcticles and have tried a lot of other options before approaching this solution, so please try to help me with this one.
Second P.S.
Sorry for my english... :)

There is no solution for compile the html into loop in angular.
maybe you need to try clean the json data you try to render and make it as simple as you can, and if you include directive inside the table, try to render it after the table is done.
also, try to isolate the reason for the slowness, disable the inline edit and all the other featers inside the table.

Use prerender.io to render the html on the server side. It basically opens a phantomjs process and executes the JS on the server, and serves the output. Works pretty well.

Related

How do I change my controller so it is decoupled enough from my view?

I'm programming a web app using Spring MVC where I need to create some elements that I cannot create directly through jsp. Specifically all of those that list values that I get from my database, since I cannot create a structure in jsp before knowing its size. Here's how I'm doing it right now:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView getAllEjercicios (...)
...
Table table = new Table("table_ejercicios", "table_ejercicios", new ArrayList<TableHead>(Arrays.asList(tH1, tH2, tH3)), getEjercicioTableContent(ejercicioList));
...
model.put("table", table.getCode());
return new ModelAndView("ejercicio/ejercicio-list", MODEL_NAME, model);
This is my controller method, where Table is a custom class that I created that will return the html code of the table when calling getCode(), using the parameters it was given. The problem with this is that I'm starting to see my Controller is not decoupled enough, since it's passing the view the HTML code of the entire object instead of just the parameters I need in order to build it in my jsp file. Btw, this is not just an issue with this particular table, I have other dropdown lists and things as such in my code.
The problem is that if I use a javascript function which receives the same parameters as my table inside the jsp, I'll have to replicate a lot of code in other views that use similar tables, since I'll have to copy the entire javascript function in each jsp file.
My code works perfectly, it's not a problem of it not working, it's a problem of structure.
What should I do, should I keep my code as it is, or is there a solution I'm not thinking of?
Thanks
The html pages, contains lots of elements, such as tables, forms, dropdown,... . If you generate all UI elements in the backend, your server side code will full of client side coding! This is not a good practice as you already know.
I think the best practice is rendering html pages without any extra UI elements, just html code with data. You can even exclude data from page and fill html elements with data from ajax request. However, your controller will completely free from UI codes. With this approach, your concern is duplication of codes in the client side. This can be solved with generating javascript utilities. For example, you have same html table structure in multiple pages. For doing this, you can write a javascript function for generating table. This function can take some parameters and add dynamic table to every page you need. You can do similar works for other elements such as forms and dropdown.

How to remove the html generated from razor var to Javascript variable?

I'm using MVC5 and passing model from Controller to View. In the view I have
var test = #Html.Raw(Json.Encode(Model.Data));
It work great, I have my model in the js variable. The problem is when I'm going to see my HTML code, the whole variable is rendered
Is there any way how I can remove or hide this code?
Thanks
To pass a variable from your server to the client you have two options really:
Do what you have done (but the value is rendered in markup)
Expose a webapi and query the endpoint in javascript to get the data
Option 2 is best practice.
Without more details on what you're trying to achieve I can't give a more detailed answer, but basically you should be looking into webapi to resolve this.
note: there are other things you could do like websockets and cookies, but it's unlikely that you want that kind of stuff for this

Accessing javascript variables inside partial in handlebars.js / express-handlebars

First of all, sorry to ask a question that has been asked in similar ways before. I just can;t get any of the solutions to work for me.
I am using handlebars.js with the express-handlebars library in node.js. I have both server and client rendering set up correctly and can render partials with data passed in through routers with no problem.
However I am struggling to access the page context and render javascript data declared in a script in the page.
Page snippet:
<script type="application/javascript">var hash = {
var1:'this is the data I want to render',
var2: 'this is some more data i want to render'}</script>
<div id="thisdiv">
{{> blag this.hash}}
</div>
Partial 'blag':
<div class="blag-partial">
{{this.var1}}
{{this.var1}}
</div>
I cannot get the value var1 in my hash variable to render.
If i pass a hard coded string to the partial then it works with no problem, but I can never seem to access what i would call 'page context'.
What am I doing wrong that I can never seem to get this to work?
I have tried...
Passing 'this' as the context into the partial
Using the '../variablename' syntax to pass it into the partial
Send key value pairs into the partial
Accessing variable from context using the # symbol in both the partial call and inside the partial itself
...and many other combinations of these things. With 100% failed attempts except when I pass in a hard-coded string.
Any help would be really appreciated. I feel like this should be simple.
OK, so to resolve this problem I needed to change the JavaScript to actually grad a reference to the div i wanted the output in and inject then call the template with the data I wanted passed as an argument to the template
var hash1 = {
var1:'this is the data I want to render',
var2: 'this is some more data i want to render'};
document.querySelector('#thisdiv').innerHTML = blagTemplate(hash1);
And I changed my partial definition to :
<div class="blag-partial">
{{#with this}}
{{var1}}
{{var2}}
{{/with}}
</div>
My second mistake was that I thought I could inline this script inside a script tag in the page but it doesn't work at all.
I think my biggest mistake was in thinking that the 'express-handlebars' npm module was actually doing more for me than it actualy is doing.
In reality...it automatically compiles my templates and partials in any of the directories I specify and that's about it.
So when I look at tutorials like like https://www.youtube.com/watch?v=4HuAnM6b2d8 for example, I still need to do the same process really...I can just skip the compilation process because thetemplates / partials were already compiled in my express node server.
Now I realize this it's ok, I just misunderstood what I should expect.
If anybody has any knowledge to the contrary, please feel free to share.
I hope this can help at least 1 person, because it frustrated me for hours! :)

Persistent templates (or re-using templates) with Hogan / Mustache?

Not entirely sure if "persistent templates" is what I am after, this is the first time I am using a Javascript templating engine. I am curious if there is a way of keeping the template data intact for the purposes of re-rendering a document once it has been rendered...
An example -- I define a simple template snippet:
<div id="price">Price: {{current_price}}</div>
I render it:
var template = Hogan.compile($("#price").html())
$("#price").html(template.render(price_data))
Let's say I want to update the price information every X seconds (fire a request, grab JSON and push it back to #price), re-rendering the template fails as there is no {{current_price}} any more. I could just do something along the lines of $('#price').text('Price: ' + price_data) after a succesful request but I feel this somehow makes the idea behind using templates useless.
So the question is, what is a way to re-use templates on a document? Cache the template data into a variable and re-use it when rendering or is there a more clever way?
Thanks.
You shouldn't be using a thing as its own template, you'll run into all sorts of problems (especially once you start adding mustache tags to attributes, or conditionally showing html tags, or anything like that).
Make your template its own element on the page. And do yourself a favor and use a <script type="text/x-mustache"> tag for it.

How do I reduce view duplication between client and server?

I'm working on an AJAXy project (Dojo and Rails, if the particulars matter). There are several places where the user should be able to sort, group, and filter results. There are also places where a user fills out a short form and the resulting item gets added to a list on the same page.
The non-AJAXy implementation works fine -- the view layer server-side already knows how to render this stuff, so it can just do it again in a different order or with an extra element. This, however, adds lots of burden to the server.
So we switched to sending JSON from the server and doing lots of (re-)rendering client-side. The downside is that now we have duplicate code for rendering every page: once in Rails, which was built for this, and once in Dojo, which was not. The latter is basically just string concatenation.
So question part one: is there a good Javascript MVC framework we could use to make the rendering on the client-side more maintainable?
And question part two: is there a way to generate the client-side views in Javascript and the server-side views in ERB from the same template? I think that's what the Pragmatic Programmers would do.
Alternatively, question part three: am I completely missing another angle? Perhaps send JSON from the server but also include the HTML snippet as an attribute so the Javascript can do the filtering, sorting, etc. and then just insert the given fragment?
Well, every time you generate HTML snippets on the client and on the server you may end up with duplicated code. There is no good way around it generally. But you can do two things:
Generate everything on the server. Use AHAH when you need to generate HTML snippets dynamically. Basically you ask server to generate an HTML fragment, receive it asynchronously, and plug it in place using innerHTML or any other similar mechanism.
Generate everything on the client (AKA the thick client paradigm). In this case even for the initial rendering you pass data instead of pre-rendered HTML, and process the data client-side using JavaScript to make HTML. Depending on the situation you can use the data island technique, or request data asynchronously. Variant: include it as <script> using JSONP so the browser will make a request for you while loading the page.
Both approaches are very simple and have different set of pros and cons. Sometimes it is possible to combine both techniques within one web application for different parts of data.
Of course you can go for exotic solutions, like using some JavaScript-based server-side framework. In this case you can share the code between the server and the client.
I don't have a complete answer for you; I too have struggled with this on a recent project. But, here is a thought:
Ajax call to Rails
Rails composes the entire grid again, with the new row.
Rails serializes HTML, which is returned to the browser.
Javascript replaces the entire grid element with the new HTML.
Note: I'm not a Rails person, so I'm not sure if those bits fit.
Has anyone tried something like the following? There's redundant data now, but all the rendering is done server-side and all the interaction is done client-side.
Server Side:
render_table_initially:
if nojs:
render big_html_table
else:
render empty_table_with_callback_to_load_table
load_table:
render '{ rows: [
{ foo: "a", bar: "b", renderedHTML: "<tr><td>...</td></tr>" },
{ foo: "c", bar: "d", renderedHTML: "<tr><td>...</td></tr>" },
...
]}'
Client side:
dojo.xhrGet({
url: '/load_table',
handleAs: 'json',
load: function(response) {
dojo.global.all_available_data = response;
dojo.each(response.rows, function(row) {
insert_row(row.renderedHTML);
}
}
});
Storing the all_available_data lets you do sorting, filtering, grouping, etc. without hitting the server.
I'm only cautious because I've never heard of it being done. It seems like there's an anti-pattern lurking in there...
"Perhaps send JSON from the server but also include the HTML snippet as an attribute so the Javascript can do the filtering, sorting, etc. and then just insert the given fragment?"
I recommend keeping the presentation layer on the client and simply downloading data as needed.
For a rudimentary templating engine, you can extend Prototype's Template construct:
http://www.prototypejs.org/api/template
As your client scales and you need a rich and flexible MVC, try PureMVC.
http://puremvc.org/content/view/102/181/
As in regular server side programming you should strive to encapsulate your entities with controls, in your case client side controls that has data properties and also render methods + events.
So for example lets say you have on the page an are that shows tree of employees, effectively you should encapsulate it behavior in a client side class that can get JSON object of the employee list / by default connect to the service and a render method to render the output, events and so on.
In ExtJS its is relatively easy to create these kind of controls - look at this article.
Maybe I'm not fully understanding your problem but this is how I would solve your requirements:
Sort, Filter
It can be done all in JavaScript, without hitting the server. It's a problem of manipulating the table rows, move rows for sorting, hide rows for filtering, there is no need for re-rendering. You will need to mark columns with the data type with custom attributes or extra class names in order to be able to parse numbers or dates.
If your reports are paginated I think it's easier and better to refresh the whole table or page.
Group
I can't help here as I don't understand how will you enable grouping. Are you switching columns to show accumulates? How do you show the data that doesn't support accumulates like text or dates?
New item
This time I would use AJAX with a JSON response to confirm that the new item was correctly saved and possibly with calculated data.
In order to add the new item to the results table I would clone a row and alter the values. Again we don't need to render anything in client-side. The last time I needed something like this I was adding an empty hidden row at the end of the results, this way you will always have a row to clone no matter if the results are empty.
Number 5 in my list of five AJAX styles tends to work pretty well.

Categories

Resources