Angular template use non-html language - angularjs

I am using express server and angular client. I use jade to write express template and the code is very clean.
for example, in index.jade
html
head
title!= title
body
h1!= message
Then I can just compile the jade file into html file
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!'});
});
Now I am moving some logic to the client to prevent page loading. The drawback is that angular template is as verbose as normal html code. Files get long and messy soon.
For example, in my profile template, I have this
<div class="my-panel-body">
<table class="my-table">
<!--email-->
<tr>
<th>Email</th>
<td>{{entity.email}}</td>
</tr>
<!--gender-->
<tr>
<th>Gender</th>
<td>{{entity.meta.gender}}</td>
</tr>
<!--dob-->
<tr>
<th>Date of Birth</th>
<td>{{entity.meta.dob}}</td>
</tr>
<!--country-->
<tr>
<th>Country</th>
<td>{{entity.meta.country}}</td>
</tr>
<!--city-->
<tr>
<th>City</th>
<td>{{entity.meta.city}}</td>
</tr>
<!--status-->
<tr>
<th>Status</th>
<td>{{entity.meta.status}}</td>
</tr>
It would be great if I can write things like
div
table
head
tr
th Date of Birth
td {{entity.dob}}
tr
th Email
td {{entity.email}}
It doesn't have to be jade. I am ok with any language as long as its clean and short

Jade runs on the server and Angular runs on the client. When Angular requests the template, it will ask the server and the server will process the Jade template and respond with the generated HTML which is then a valid Angular template.
As long as you're not using any kind of pre-processor to package the Angular templates into a single file, then using Jade on the server to generate Angular templates for the client works fine. If you are using a pre-processor, then you need to run Jade first (which is also possible--Jade is not tied to Express).
Not necessarily related to this question, but it's also useful to note that Angular is not tied to HTML. Any tag based language that the browser supports will work with Angular--SVG, VRML, MathML, etc.

So what you can do is write them how you want and then before angular loads create a module called templates that uses $templateCache. You can put them in there once they're parsed: https://docs.angularjs.org/api/ng/service/$templateCache
If you need it rendered on the fly you'll have to modifiy how $http.get works in your .config and check to see if it's a template and if it is pass it through your renderer.

Related

How to make a table sort-able while the whole components is passed as string via ng-bind-html in AngluarJS

Hi I have a situation in AngluarJS that the HTML is generated by back-end and the only thing that front-end should do is to put the HTML which is mostly table tags into the ng-bind-html and show it to the user. But now these tables should be sort-able too. How can I do it?
The thing that I've already done is to create my own directive using this so make the static string HTML take some actions too. But having them sorted is something else. In other word I want to make my fully generated table with all <tr> and <td> to get sorted by my actions.
Here is my simplified code (compile is my directive):
JS:
// The string is fully generated by back-end
$scope.data.html =
'<table> <tr> <th ng-click="sortByHeader($event)"> Name </th>
<th ng-click="sortByHeader($event)"> Age </th> </tr>
<tr> <td> Sara </td> <td> 15 </td> </tr>
<tr> <td> David </td> <td> 20 </td> </tr>'
HTML:
<div compile="data.html"></div>
The ng-click="sortByHeader($event) is something that back-end can prepare for me so I can use it thanks to the compile I wrote that let me find out which header has been clicked. Other than that there is nothing I can do. Unless you can help me :D
Thanks in advance, I hope my question was clear.
Since you tagged your question with sorttable.js I'm going to assume that you are using that script to sort your tables.
Now, if I understand it correctly, sorttable.js parses your HTML for any tables with the class sortable. Your table is apparently loaded dynamically, therefore sorttable.js does not know about it when it parses the HTML.
But you can tell it to make a dynamically added table sortable, too.
Relevant part taken from the following page:
https://kryogenix.org/code/browser/sorttable/#ajaxtables
Sorting a table added after page load
Once you've added a new table to the page at runtime (for example, by
doing an Ajax request to get the content, or by dynamically creating
it with JavaScript), get a reference to it (possibly with var
newTableObject = document.getElementById(idOfTheTableIJustAdded) or
similar), then do this:
sorttable.makeSortable(newTableObject);
You should be able to do that with angular. If not, I can try to put something together later.
Is the answer to the question "Does the rendered table have to exactly match the HTML retrieved by the backend?" a kind of "No"?
If that's the case, then here's a hacky way of gaining control of the table contents by parsing and capturing stuff from the backend HTML string using regular expressions.
For example: grab all row data and apply sorting client side
// Variables to be set by your sortByHeader functions in order to do client-side sorting
$scope.expression = null;
$scope.direction = null;
var regexToGetTableHead = /<table>\s*(.*<\/th>\s*<\/tr>)/g;
$scope.tableHead = regexToGetTableHead.exec($scope.data.html);
$scope.tableRows = [];
var regexToGetRowContents = /<tr>\s*<td>\s*(\w*)\s*<\/td>\s*<td>\s*(\w*)\s*<\/td>\s*<\/tr>/g;
var match;
while ((match = regexToGetRowContents.exec($scope.data.html)) != null) {
$scope.tableRows.push({
"name": match[1],
"age": match[2]
});
}
And HTML
<table>
<thead compile="tableHead"></thead>
<tbody>
<tr ng-repeat="row in tableRows | orderBy: expression : direction">
<td>{{row.name}}</td>
<td>{{row.age}}</td>
</tr>
</tbody>
</table>

Bootstrap pagination on ng-repeat

I have a table where I'm listing my restaurants
<table class="table">
<tbody>
<tr ng-repeat="row in restaurantList">
<td><img src="{{row.image}}"></td>
<td>{{row.name}}</td>
</tr>
</tbody>
<table>
I'm getting all the names and photos correctly. But how can I paginate the collected data, 10 by 10 in bootstrap without plugins ?
If you are using both angularjs and bootstrap, it would be interesting for you to also use the bootstrap-ui library.
It is really easy to use and it provides a lot of UI components (one of them is a pagination directive).
I don't know if it is what you mean when you say "without plugins" ? That's just one js file to load in your site, and you already have all the required dependencies.
I hope it helps

Grails and Angular: GSP plugin tag inside ng-repeat loop

I'm working in a Grails project that uses Angular.
I use a plugin called PrettyPrint in order to have "twitter like" time (i.e. formatting dates like 'moments ago').
I want to use the plugin inside a ng-repeat loop.
<tr ng-repeat="notification in notifications">
...
<td><prettytime:display date="${notification.date}" /></td>
...
</tr>
In the above code, the error thrown is Cannot get property 'date' on null object. (it doesn't recognize notification item from angular loop).
If I use {{notification.date}} it shows the date.
How can I deal with both, the plugin and Angular?
Put simply, you can't.
One is browser based and the other is server based. You can't use the plugin, which is server based, and call it from JavaScript in the browser.
Think it through. The ng-repeat loop is being done by the browser. When this happens the server has already finished processing the GSP and sent it to the browser. There is no opportunity for the plugin to be called then.
You will have better luck taking the date from the server and parsing it in the browser and using a browser based plugin which offers the same functionality as the Grails plugin for date formatting.
Try this code in your gsp (assume you have passed notifications list to the view via the model):
<%
def notifications = notificationsFromModel.collect {
[date: prettyTime.display(it.date), message: it.message]
}
%>
<span ng-init="notifications = <%= notifications as JSON %>"></span>
<tr ng-repeat="notification in notifications">
<td>{{ notification.date }}</td>
<td>{{ notification.message }}</td>
</tr>

mdVirtualRepeatContainer can't be found

Trying to get md-virtual-repeat to work but getting in the console:
Controller 'mdVirtualRepeatContainer', required by directive 'mdVirtualRepeat', can't be found!
I have a <md-virtual-repeat-container> with a <tr md-virtual-repeat="row in table" md-item-size="25"></tr> inside of it. Working with angular-material 0.10.1 and angular 1.4.2.
Try to put md-virtual-repeat-container as attribute of tbody.
I also encountered this error but then changed to this code and it works:
<tbody md-virtual-repeat-container>
<tr md-virtual-repeat="user in Impl.users">
<td>{{::user.fname}} {{::user.lname}}</td>
</tr>
</tbody>
Although this crappy directive creates div inside tbody and it breaks table rendering. Same shit as with md-tabs.

Does Bootstrap3 work with Firefox v25.0.1 and AngularJS? FireFox not displaying table

I am running AngularJS 1.2.3 and Bootstrap3 to create a simple task list app.
The code and Bootstrap3 CSS works everywhere (IE11.x, Chrome v31.0.1650.63 m, Opera v18.0.1284.63), except FireFox 25.0.1
If I add the link to bootstrap3 via
<link href="3rdPartyLibs/bootstrap3/css/bootstrap.min.css" rel="stylesheet">
then when AngularJS ng-repeat runs to create the table rows then FireFox v25.0.1 does not render the table header or rows and display them to the user However, if you look at the source, they are being created.
Here's an image of the page and an image of the source:
It should look like this:
FireFox displays this (notice there are no rows):
In FireFox, if I click the [Add New Task] button numerous times, it actually alters the DOM as I expect it to (adding rows to the table), but it doesn't display that to the user. However, the source is altered -- rows are added to the table -- and the source looks like this:
Referencing Bootstrap2 Makes It Work
All I have to do to make it work is reference Bootstrap2 on my machine (i have both locally) by altering the link to : (notice there is no 3 in the bootstrap directory.
<link href="3rdPartyLibs/bootstrap/css/bootstrap.min.css" rel="stylesheet">
After I do that, it works in FireFox too and looks like:
Does bootstrap3 work in FireFox? Is there some special initialization I have to do?
Is Bootstrap3 not ready for prime-time, or is it FireFox?
Figured It Out While Attempting To Convert To Bootstrap2
I decided to convert this thing to work with Bootstrap2 since that would mean all browsers would work. While doing that I discovered that if I simply add a wrapper to my table, then it fixes the problem.
Here's a summary of what I had and what I did:
***note:**If you see unclosed tags, that is bec. it's a summary, please don't try to tell me I need to close those tags. It is valid HTML in the real thing. thanks.*
I had
<html>
<div>
<button1>
<button2>...
</div>
<table>
<thead>
<th>
</thead>
<tbody>
<tr ng-repeat="t in allTasks"
</tbody>
</table>
</html>
I simply wrapped my table in another div and now it works in FireFox. Looks like this:
<html>
<div>
<button1>
<button2>...
</div>
<div>
<table>
<thead>
<th>
</thead>
<tbody>
<tr ng-repeat="t in allTasks"
</tbody>
</table>
</div>
</html>
Now it looks like it should in FireFox

Resources