jQuery With Mustache js Issue - javascript

I'm using jQuery and Mustache Js in a project.
I have the template in a script tag. The template requires some dynamic/variable html based on some data. Hence I load the template using jQuery, manipulate it, and then write it back into the script tag.
However, loading the template into a div(for manipulation), using jquery seems to alter the structure of the template (it moves things around), which invalidates the template.
How do i update the template dynamically and avoid this issue? (Any help / Pointers / etc)
Original Template
<table>
<thead>
<tr>
<td>FN</td>
<td>SN</td>
<td>OT</td>
</tr>
</thead>
<tbody>{{#Users}}
<tr class="tr-border" data-row-id="{{DCSID}}">
<td class="td-border">{{FN}}</td>
<td class="td-border">{{SN}}</td>
<td class="td-border">{{OT}}</td>
</tr>{{/Users}}</tbody>
</table>
Loading with jquery into another div causes this below(moves {{#Users}} {{/Users}} out of place)
{{#Users}} {{/Users}}
<table>
<thead>
<tr>
<td>FN</td>
<td>SN</td>
<td>OT</td>
</tr>
</thead>
<tbody><tr class="tr-border" data-row-id="{{DCSID}}">
<td class="td-border">{{FN}}</td>
<td class="td-border">{{SN}}</td>
<td class="td-border">{{OT}}</td>
</tr></tbody>
</table
The code below is how I'm going about it. Also this is a js fiddle link here
var $newDcsTemplate = $('<div/>').html($('#dcs-template').html()); // for manipulation
var original1 = $('#dcs-template').html()
var original2 = document.getElementById('dcs-template').innerHTML;
// manipulate the template here and replace content of script tag with it.
console.log(original1); // works fine
console.log(original2) // works fine
console.log($newDcsTemplate.html()) // messed up the template

Do it like this, with .html() and without </script>:
<table>
<thead>
<tr>
<td>FN</td>
<td>SN</td>
<td>OT</td>
</tr>
</thead>
<tbody>
<!-- {{#Users}} -->
<tr class="tr-border" data-row-id="{{DCSID}}">
<td class="td-border">{{FN}}</td>
<td class="td-border">{{SN}}</td>
<td class="td-border">{{OT}}</td>
</tr>
<!-- {{/Users}} -->
</tbody>
</table>

Your template is being modified by the DOM because you're inserting it into a <div> as "HTML", which it isn't. It's doing exactly what a browser would do if you gave it that markup. It's putting the {{# Users }} in the nearest available valid place to put it.
This is the same reason your template is originally stored in a <script> tag. You should always use <script> tags to hold your templates, and you should always use .text() to read and write them:
var $newDcsTemplate = $('<script/>').text($('#dcs-template').text());
console.log($newDcsTemplate.text())

Related

Using JavaScript variables in a Thymeleaf th:each

I am trying to build a table using th:each and have the whole row of the table clickable as a link through JavaScript.
<table>
<th:block th:each='user : ${list}'>
<script th:inline="javascript">
var userid = [[${user.id}]];
</script>
<tr onclick="location.href='user?id='+userid">
<td th:text="${user.firstName}"></td>
<td th:text="${user.lastName}"></td>
</tr>
</th:block>
</table>
However, the variable always refers to the latest value and not the one it was when the row was created. Is there a way to do that? Or maybe a different solution to what I'm trying to do?
No need for the th:block, you can simply put the th:each on the tr.
To accomplish the click, I recommend putting the id in a data attribute, and retrieving it in JavaScript. This should work for you:
<table>
<tr th:each="user : ${list}"
th:data-id="${user.id}"
onclick="location.href = 'user?id='+this.getAttribute('data-id')">
<td th:text="${user.firstName}"></td>
<td th:text="${user.lastName}"></td>
</tr>
</table>
You can avoid using JavaScript by adding an <a> element to each table cell (Inspired by https://stackoverflow.com/a/17147909/40064):
<table>
<th:block th:each='user : ${list}'>
<tr>
<td><a th:href="#{/user(id=${userid})}" th:text="${user.firstName}"></a></td>
<td><a th:href="#{/user(id=${userid})}" th:text="${user.lastName}"></a></td>
</tr>
</th:block>
</table>

How to search through a table and pull the data?

I'm new to js, I'm working on a chrome extension and am having confusion webscraping a website. Suppose I have a simple table in an html like this
<html>
<body>
<table class="birthdays">
<tbody><tr>
<th>date</th>
<th>month</th>
<th>year</th>
</tr>
<tr class="r0">
<td>Person</td>
<td>1</td>
<td>Jan</td>
<td>77</td>
<td colspan="3"></td>
</tr>
<tr class="r0">
<td>Person</td>
<td>1</td>
<td>Jan</td>
<td>77</td>
<td colspan="3"></td>
</tr>
</tbody></table>
</body>
</html>
In my chrome extension when I do
const x = document.getElementsByTagName("th")[0][0]
alert(x)
It says it found a th object, but doesn't give me the actual data. That's the first issue, my actual goal is to determine if all elements in the tr tags have the same of one property (ex. if everyone has their birthday in Jan, open a tab).
document.getElementsByTagName
returns HTMLCollection https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
it's an array-like object (not real array)
and you can get the value from it calling item() method https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection/item
Seems that you need something like this document.getElementsByTagName("th").item(0).innerHTML to get content of the first TH tag
This is not a complete answer, but in javascript the container is not its contents - i.e. you need document.getElementsByTagName("th")[0][0].innerHTML to get at the 'date' string.

Get multiple Angular.js controllers for multilple <td> within the same <tr>

I'm trying to add multiple angular controllers within the same tr tag, the problem is that chrome rewrites the table to standardize it, and there is no element between tr and td in the HTML table hierarchy.
Here is what I currently have, each color represents a different controller to call.
The final aim is to have a table like below, with a different controller for one or multiple td, instead or multiple trs
I know I could use a global controller to handle all the data, or use multiple div elements with a fixed width to achieve this, but I'd prefer using a single tr table.
Here is the code :
<table>
<tr>
<div ng-controller="testController">
<td>{{testcontrollerscopevalue}}</td> <!-- empty when displayed -->
<td>{{testcontrollerscopevalue2}}</td> <!-- empty when displayed -->
<td>{{testcontrollerscopevalue3}}</td> <!-- empty when displayed -->
</div>
<div ng-controller="testController2">
<td>{{testcontroller2scopevalue}}</td> <!-- empty when displayed -->
</div>
</tr>
</table>
The following works :
<table ng-controller="testController">
<tr>
<td>{{testcontrollerscopevalue}}</td> <!-- set when displayed-->
</tr>
</table>
Here is what chrome generates :
<body>
<div ng-controller="testController"></div>
<div ng-controller="testController2"></div>
<table>
<tbody>
<tr>
<td>{{testcontrollerscopevalue}}</td> <!-- out of scope-->
<td>{{testcontrollerscopevalue2}}</td> <!-- out of scope-->
<td>{{testcontrollerscopevalue3}}</td> <!-- out of scope-->
<td>{{testcontroller2scopevalue1}}</td> <!-- out of scope-->
</tr>
</tbody>
</table>
<table ng-controller="testController">
<tbody>
<tr>
<td>{{testcontrollerscopevalue}}</td> <!-- set -->
</tr>
</tbody>
</table>
Is there any way I can achieve this ?
Is there any tag I could use instead of div to get this to work?
Thanks,
As we discussed at length in the chat session, This is a case where you are best served by using the ControllerAs Syntax, and wrapping the <table> element in multiple <div> elements holding each controller's logic.
My suggestion was something similar to the following code:
<div ng-controller="testController as tc">
<div ng-controller="testController2 as tc2">
<table>
<tbody>
<tr>
<td>{{tc1.testcontrollervalue}}</td>
<td>{{tc1.testcontrollervalue2}}</td>
<td>{{tc1.testcontrollervalue3}}</td>
<td>{{tc2.testcontroller2value1}}</td>
</tr>
</tbody>
</table>
</div>
</div>
For this to work, your variables need to be converted to be properties of the controller, rather than properties of $scope.
var tc1 = this; //consistent reference to controller object
SomeService.get(function(data) {
tc1.someProperty = data;
});
You should probably just do:
<td ng-controller="testController2">{{testcontrollerscopevalue}}</td>
If you really need the div:
<td><div ng-controller="testController2">{{testcontrollerscopevalue}}</div></td>

Vue.js block repeat table rows doesn't work in IE

I would like to repeat adding table rows using a template tag with vue.js, but it doesn't work in IE11. Here is the code.
<table border="1">
<tr>
<td rowspan="2">ID</td>
<td colspan="2">Name</td>
</tr>
<tr>
<td>Height</td>
<td>Weight</td>
</tr>
<template v-repeat="items">
<tr>
<td rowspan="2">{{id}}</td>
<td colspan="2">{{name}}</td>
</tr>
<tr>
<td>{{height}}</td>
<td>{{weight}}</td>
</tr>
</template>
</table>
Any help?
See http://vuejs.org/guide/components.html#Using_Components and the warning at the end of that section:
The table element has restrictions on what elements can appear inside
it, so custom elements will be hoisted out and not render properly. In
those cases you can use the component directive syntax:
<tr v-component="my-component"></tr>.
I found a solution that changed the <template> tag to a <tbody> tag. However there would be multiple <tbody> tags in a table, I hope this is the best solution in this case.
Make a long story short, This is HTML restrictions in IE, if you want compatibility, you will have to change your HTML structure.
I found an issue with similar question like yours here: https://github.com/vuejs/vue/issues/2404
Vue renders the template into real html before compiling it, so the same html restrictions apply for Vue templates, no matter how you define it.
IE does not support inside elements like , ..

Generating pure html using AngularJS

I'm trying to extract a raw HTML table of data from a table which I currently generate on a web page using AngularJS.
To give a simple example:
Angular code:
<table>
<tr ng-repeat="customer in customers">
<td>{{customer.firstname}}</td>
<td>{{customer.lastname}}</td>
</tr>
</table>
I don't want to code two different solutions and so would like to use AngularJS.
Is it possible to extract the raw html code using AngularJS? i.e. the following :
<table>
<tr>
<td>John</td>
<td>Smith</td>
</tr>
<tr>
<td>Fred</td>
<td>Bloggs</td>
</tr>
...etc
</table>
you can use
var element = angular.element(element)
element[0] //show give raw dom element
refer jqlite and below link in angularJS , probably will get idea https://docs.angularjs.org/api/ng/function/angular.element
Fiddle: https://jsfiddle.net/shushanthp/Lho8myw2/

Categories