Tablesaw in AngularJS - javascript

I've been trying to use filamentgroup's tablesaw ( https://github.com/filamentgroup/tablesaw ) in angularJS (I really love this feature filled table), but i have no idea how to start. Many articles seems to point towards using AngularJS's directives in converting existing JQuery plugins to Angular's Directives. Does that mean for every JQuery tag i'm using from Tablesaw, i have to rewrite the entire JQuery function from Tablesaw over to Angular?
Understanding that Angular wants us to avoid DOM manipulation from JQuery, and to rethink how we develop our apps. However, it doesn't make sense to forego hundreds of well done JQuery libraries available online and just waste time and effort to rewrite libraries to work in the way Angular wants.
Really appreciate anyone to kickstart me with JQuery TableSaw and Angular. Thanks in advance!

I got tablesaw to work for a table where the rows are generated by ng-repeat with the following directive:
app.directive("tableSaw", ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function($scope, element, attr) {
if($scope.$last === true) {
$timeout(function () {
$(document).trigger("enhance.tablesaw");
});
}
} // end link
};
}]);
The key being the call to tablesaw only works after the complete table has been rendered, this is why I am applying the directive row-wise, so it can initiate tablesaw only after the final row has been rendered.
Here's my table (note the table-saw directive applied alongside ngRepeat):
<div id="myContainer" ng-controller="AdminUserListCtrl as vm">
<table id="myTable"
class="tablesaw tablesaw-stack" data-tablesaw-mode="stack">
<thead class='study-list-header'>
<tr>
<th scope="col" data-tablesaw-sortable-col>
Name
</th>
<th scope="col" data-tablesaw-sortable-col>
Email
</th>
</tr>
</thead>
<tbody id="studyListData">
<tr class="study-list-row"
ng-repeat="elem in vm.usersList"
table-saw>
<td>{{elem.last_name}}, {{elem.first_name}}</td>
<td>
{{elem.email}}
</td>
</tr>
</tbody>
</table>
</div>
My includes are:
require('jquery');
require('../../node_modules/tablesaw/dist/tablesaw.css');
require('../../node_modules/tablesaw/dist/tablesaw.jquery.js');
I do not include tablesaw-init.js (it results in an error and should be absent in the case of manual initialization as specified in their docs).
A note on the call to $(document). The docs in the tablesaw git page specify that for manual initialization of tablesaw on an element we should call trigger("enhance.tablesaw") on any parent element and tablesaw will scan the tree and enable itself on all child elements that have the correct tablesaw markup. It is up to you if you want to call it on $document or perhaps on some kind of predefined parent element.

Related

Make html layout and use it with JS

I have a table with some data:
<table id="myTable">
<thead>
<tr>
<th><h1>Name</h1></th>
<th><h1>Picture</h1></th>
<th><h1>Likes</h1></th>
<th><h1>Time</h1></th>
</tr>
</thead>
<tbody>
***loop***
<tr>
<td>{placeholder1}</td>
<td><img src="{placeholder2}" alt=""></td>
<td>{placeholder3}</td>
<td>{placeholder4}</td>
</tr>
***end loop***
</tbody>
</table>
I have a js function who gets some data from server by POST request every 10 minutes. <tr></tr> block needs to be repeated several times.
HTML code become more and more complex and I need a solution with layouts and placeholders. I need a direction to search :)
All I need is:
Store <tr></tr> pattern with placeholders to insert it into my webpage. How could I achieve it with js?
How could I mark the places where I need data to be inserted?
Okay since you are using jQuery,
This may be your HTML
<table>
<tbody id="myTableBody">
<!-- Your elements will be placed here -->
</tbody>
</table>
I will assume you are using $.ajax or $.post in either of those, add a callback function property success
$.ajax({
// ... your properties,
success: function(data) {
// basic template for of your "tr"
var trTemplate = [
'<tr>',
'<td></td>',
'<td><img src="" alt=""></td>',
'<td></td>',
'<td></td>',
'</tr>'
].join('')
// get the tbody elemen
var $myBody = $('#myTableBody')
// if you want to clean up the current content of $myBody,
// if it is not the case just remove the following line
$myBody.empty()
// assuming data is an array of elements / entities
data.forEach(function(element){
var $tr = $(trTemplate)
$tr.find('td').eq(0).text(element.placeholder1)
$tr.find('img').attr('src', element.placeholder2)
$tr.find('td').eq(2).text(element.placeholder3)
$tr.find('td').eq(3).text(element.placeholder4)
$myBody.append($tr)
})
}
})
This is example of how you could do it, there are many ways to improve this for performance and so on. Please use it only as reference
If you're using jQuery then this is pretty straightforward. You need to id your elements so that you can reference them individually. Say you start with:
<tr id="tr-0" >
content...
</tr>
and then in javascript..
var id = $('#tr-0').attr('id');
var num = parseInt(id.substring(3));
num++;
$('#tr-0').after('<tr id='+num+'>content...</tr>');
obviously you need to figure how you're getting the content for each row but hopefully you can see that it wouldn't be too hard to fill each row with custom data.
Although you can use jQuery, simpler ways exist. jQuery will require you to add additional steps that aren't really necessary. If you want to use as few Javascript packages as possible, go with jQuery.
But, I highly recommend Vue.js for Laravel projects. There are instructions from Laracasts on how to set it up. But, I have created a jsfiddle with a working set of Vue.js with the v-for directive. Checkout the JSFiddle here.
If you have questions, I'll answer as much as I can.

ui-grid: trigger sorting in custom header template

I use the following in order to implement custom column headers for my grid:
<div role="columnheader">
<table class="table-header-rotated">
<theader>
<tr>
<th class="op-table-group-heading rotate-45">
<div class="op-table-group-heading-title rotated-container"
ng-class="{inclined : col.headerCellClass}">
<span>{{col.headerCellClass}}</span>
</div>
</th>
</tr>
<tr>
<th class="op-table-asset-heading rotate-45">
<div class="rotated-container colt{{col.uid}}">
<span>{{col.displayName}}</span>
</div>
</th>
</tr>
</theader>
</table>
</div>
However, clicking on this header does not trigger any change to the sorting. A (probably outdated) article in the wiki suggests to use col.sort() in order to do so. However, doing this fails with v2.sort is not a function.
I have looked at the source code for the current default header templates in ui-grid 3. However, I can find no ng-click in it that would trigger the sort event, so I can only assume they are binding their click listeners somehwere else.
How do I go about enabling sorting in my custom template?
Alright, so after dissecting the original template, it seems that the one crucial component needed to trigger sorts when clicking the header is ui-grid-cell-contents class. Thus, the minimum header template that can be used for sorting is simply <div class="ui-grid-cell-contents"></div>

loading common templates into an html page with angular

I have a page which contains detail sections that are common across multiple pages of my app. I am trying to reduce code redundancy and create these mini views that will be loaded with the page.
In the main detail page I have a section that I am trying to load using ng-include
<div ng-show="checkProducts()">
<hr style="margin-bottom:5px!important"/>
<p><strong><em>Products</em></strong></p>
<div class="bs-associationPanel">
<ng-include src="commontemplates/productView/shoes"></ng-include>
</div>
</div>
I can't use routing here as this is acting like a partial view within the main detail page which is already using routes to load it and bind it to the controller.
The src value is a path in the APP to an html page called productView.html
I wrapped it in a script ng-template tag with an id
<script type="text/ng-template" id="shoes">
<table class="table table-condensed table-responsive">
<thead>
<tr>
<th>brand</th>
<th>color</th>
<th>size</th>
</tr>
</thead>
<tbody ng-repeat="s in detail.shoes">
<tr>
<td>{{s.brand}}</td>
<td>{{s.color}}</td>
<td>{{s.size}}</td>
</tr>
</tbody>
</table>
</script>
I was hoping this would work but when I render the page I get no temple and looking at the element explorer I see the following
<!-- ngInclude: undefined -->
I think I am close I just don't know what I am missing. Any suggestions on how this could be accomplished or Can this be accomplished?
Basically the script's with type text/ng-template are read by angular & angular consider it as template then put those templates inside $templateCache service for faster retrieval.
src attribute should have template name enclosed with ' single quotes, so that it can look up through $templateCache for getting the template.
<ng-include src="'commontemplates/productView/shoes'"></ng-include>

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 , ..

Stop a clicked link from loading and let the surrounding element with Angularjs ng-click handle the action

I have a table of courses and initially I made each row clickable, which would then switch templates in ng-view and show the course's details. My problem is that I need a search appliance's crawler to be able to follow links to the course's details in order to make them available for searching. I have done that by adding a link to the course's title in one of the table's cells but now I have the problem of having a student actually clicking both the title link and table row. Where/how do I cancel one of those actions, preferably the title link (I'd like to stop the page from loading twice)? Here is an excerpt of my template:
<thead>
<tr>
<th>Title</th>
<th>Instructor</th>
<th>Days</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="course in catalog.courses | filter:isSubject" ng-click="loadCourse(course.regnum,course.id)">
<td>{{course.abbr}} {{course.num}} {{course.section}}: {{course.title}}</td>
<td>{{course.instructor}}</td>
<td>{{course.meeting_pattern}}</td>
<td>{{course.start_time}} - {{course.end_time}}</td>
</tr>
</tbody>
When someone clicks on the link in the first cell both the link and the row's function in ng-click are called and the page loads twice. I want to stop the link href action from happening and only let the ng-click action handle the request.
I know I have to stop the propagation some how but if I stop it on the <a> element will that affect the function on the <tr> element?
Add ng-click="$event.preventDefault();" to the link that you want to stop.
<tr ng-repeat="course in catalog.courses | filter:isSubject" ng-click="loadCourse(course.regnum,course.id)">
<td>{{course.abbr}} {{course.num}} {{course.section}}: {{course.title}}</td>
<td>{{course.instructor}}</td>
<td>{{course.meeting_pattern}}</td>
<td>{{course.start_time}} - {{course.end_time}}</td>
</tr>
Also, you were missing your closing </a> on that link.
I found part of the solution here: How can I make an AngularJS directive to stopPropagation?
and used the preventDefault() instead of the stopPropagation() function.
<a href="/schedule/#!/course/{{course.regnum}}/{{course.id}}" stop-event="click">
then created a directive:
app.directive('stopEvent',function(){
return {
restrict: 'A',
link : function(scope,el,attr){
el.bind(attr.stopEvent,function(evt){
evt.preventDefault();
});
}
}
});

Categories