Is the AngularJS smart-table documentation/demo buggy? - angularjs

I just don't understand this. On the smart-table web page, where it discusses the stSafeSrc
attriubute, I don’t see where $scope. displayedCollection gets declared.
The text says smart-table first creates a safe copy of your displayed collection, and I
I had assumed that a smart-table directive was declaring it, but the sample code won’t work for me – the table rows are empty - and that’s what looks to me to be the problem.
If we look, for instance, at the accepted answer to this question, we see the user declaring $scope.displayedCollection as an empty array and assigning it a value when the AJAX response is received. BUT, the documentation doesn't mention that.
<table st-table="displayedCollection" st-safe-src="rowCollection">
<thead>
<tr>
<th st-sort="firstName">First Name</th>
<th st-sort="lastName">Last Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in displayedCollection">
<td>{{row.firstName}}</td>
<td>{{row.lastName}}</td>
</tr>
</tbody>
</table
app.controller('Ctrl', function($scope, service) {
$scope.displayedCollection = [];
service.all.then(function(list) {
$scope.rowCollection = list;
$scope.displayedCollection = list;
});
});
So, do I need to care for the copy myself? And does the documentaion need to be updated? And how does the demo work?
[Update] I find this on the github issues, by #tufan-yoc
you have to copy the data array to an other variable in the scope:
st-table="displayedCollection" st-safe-src="rowCollection"
and
//copy the references (you could clone ie angular.copy
// but then have to go through a dirty checking for the matches)
$scope.displayedCollection = [].concat($scope.rowCollection);
If this truly is a requirement, why is it not explictly documented?
And why does the example on the smart-table website work without it?

You don't need to copy anything. what you set with the attribute st-table is simply a placeholder for your templates (ie a variable in the scope) which you will likely use in the row repeater, it does not have to be declared anywhere, smart-table will assign the items to be displayed to this variable so your templates can be updated.
your source of truth (ie your data) should be the collection you bind to st-safe-src attribute. Whenever the bound collection changes, smart table will update a local copy so it can perform the filter/sort/slice operations based on the latest and actual data.
However for convenience (and performance), if you don't intend to modify your data (or its arrival is not delayed like with ajax fetch) the internal copy is firstly based on any collection bound to the variable in the scope designed by the st-table attribute.
Note in this case, the value will be erased and replaced by the displayed collection so the template is updated. Fortunately the initial copy will persist as private variable of smart-table.
If you encounter a problem it likely comes from somewhere else. If so please provide a running example (with angular version and smart table version)

No, it's not buggy. SmartTables will create an $scope.displayedCollection object or whatever name you use for the array that will hold a copy of the original data if you use the stSafeSrc attribute. If it doesn't show you any data check your rowCollection object, it should contain the original array. If you are working in Chrome try the ng-inspector for AngularJS so you can see the scope of your app. Also if you could post a plunker of your code it will be better.

We can show that the user must take action to make acopy and keep it in synch with AJAX data, by looking at this Plunk (which is not mine).
If we comment out line 18:
$scope.displayedCollection = [].concat($scope.rowCollection);
as per the online example, the table becomes empty.
Conclusion: the website documentation is wrong to say
smart-table first creates a safe copy of your displayed collection
And, bizarrely, the (working) example on the website ... should not work (?)

Related

angularjs bind function call to span without triggering event

I use ng-repeat to populate my table. One of the columns in the table should be dynamically populated again by a different function call.
Below is my code snippet.
<tr ng-repeat="item in ctrl.items">
<td><span ng-bind="item.name"></span></td>
<td><span ng-bind="getItemDetails(item.id)"></span></td>
</tr>
I have array of items. I need to display those items in a table. Item name will be present in the item object, however, item details will be populated by another function call which needs item id.
On using ng-bind (like in the code above) I face 2 issues.
Multiple calls to function even if array has 1 items. Sometimes it goes on thereby freezing my browser and server out of memory issue
The item id doesn't get passed to function always. Sometimes it is undefined.
I am not sure if ng-bind is the right directive to be used. ng-model doesn't work though. Is there any other directive or other way to do it?
How can I achieve this?
EDIT:
Here is the jsfiddle url: https://jsfiddle.net/grubxaur/
If you check browser console, you can see the function is called twice. I guess it is called N no. of times where N is no. of columns in the table.
I have tweaked my implementation a bit to get rid of this issue. Rather than calling a function within ng-repeat, I modified the items array within the controller using angular.forEach before ng-repeat is invoked.
Something like code below.
angular.forEach(self.items, function(item){
item.details = $scope.getItemDetails(item.id);
});

Can I stop Angular binding failing silently?

I have the following table markup:
<tr ng-repeat="client in clientsIndex">
<td>{{client.fullName}}</td>
<td>{{item.contactPhone}}</td>
</tr>
When the view for this renders, I see only one column is populated, but nothing logged in the console. Is there a way I can tell angular this is a debugging session, and I'd like to see big screaming error messages if I make a copy and paste mistake?
Surely at the time the {{}} expression is evaluated whatever does that can output a non-blank value at least?
As of Angular 1.1.5 there is support for ternary operators in templates. So you can define something like this to get a default value if undefined:
<tr ng-repeat="client in clientsIndex">
<td>{{client.fullName}}</td>
<td>{{item.contactPhone ? item.contactPhone : 'Error: not defined'}}</td>
</tr>
The general structure is: {{(condition) ? (expression if true) : (expression if false)}}.
For debugging purpose you can select the element using any angular.element("") selectors and see the scope of that element to check the variable you are trying to access inside the element is inside the scope available to that element.Find the example below.i have used an id selector you can use a child selector.
<tr id="canbeReplacedWithChildSelectors" ng-repeat="client in clientsIndex">
<td>{{client.fullName}}</td>
<td>{{item.contactPhone}}</td>
</tr>
angular.element("#canbeReplacedWithChildSelectors").scope() execute this and check client.fullName is available in the scope.in your case angular.element("#canbeReplacedWithChildSelectors").scope().client would give you undefined.

ngRepeat:dupes - duplicates in repeater with nested ngrepeat and empty strings

I'm working with angular building a table of data which comes from a JSON API call. I'm having to use a nested ngRepeat however I'm seeing strange results where whole table rows are missing when the row has a couple empty strings.
I can reproduce with the following plunk.
http://plnkr.co/edit/VCzzzPzfgJ95HmC2f83P?p=preview
<script>
function MyController($scope){
$scope.test = {"rows":[
["one","two","three"],
["one","two","three"],
["one","","three"],
["one","",""],
["","two",""],
["","","three"],
["one","two","three"],
["one","two","three"],
]};};
</script>
<div ng-app ng-controller="MyController">
<table>
<tr ng-repeat="(key,ary) in test.rows">
<td>{{key}}</td>
<td ng-repeat="value in ary">{{value}}</td>
</tr>
</table>
</div>
Notice when an array has two empty strings the nested ngRepeat appears to fail.
Am I going mad? Is there an explaination to this?
Yes. You would need to use track by $index since you are repeating primitives, or convert it to array of objects. Reason is ng-repeat creates unique id $$hashkey (and attached to the repeated object as property) for each of the iterated values if it is an object (unless you specify something as track by).
In your case you have primitives so it cannot attach a property itself, so it tries to consider the values repeated as identifier and it finds duplicate when you have multiple empty strings iterated. You would see the same effect when you repeat array of objects with more than one of them is undefined or null as well..
So in this case you can use track by $index So repeated items will be tracked by its index.
<td ng-repeat="value in ary track by $index">{{value}}</td>
Demo
Much better option always is to convert it to array of objects so you don't run into these kinds of issues. WHen you have a property that uniquely identifies the repeated element (say id) you can set it as track by property. When you rebind the array (or refresh the array) angular uses the tracked identifier to determine if it needs to remove the element from DOM and recreate it or just refresh the element that already exists. Many cases where a list is refreshed with the list of items it is always desirable to use a track by with an identifier on the object repeated for performance effectiveness.

Angular JS Skip OrderBy Value

I have the following code
<tr>
<th ng-click="predicate='-name'; reverse=false;">Name</th>
<th ng-click="predicate='age'; reverse=true;">Age<th>
<tr>
<tr ng-repeat="user in users | orderBy:predicate:reverse">
<td>{{user.name}}<td>
<td>{{user.age}}</td>
</tr>
My aim here is whenever i click on the table header, then the corresponding column has to be sorted based on particular predicate and reverse. And that is happening perfectly. But I have a scenario where, when i click on an external object, then my age value in table changes here and hence as a result the table sort order is getting disturbed. But i don't want sort to get disturbed. How can i skip table to not obey sort on other actions and have it only on click of table column headers? Can anyone help me with this?
I don't think this is possible. Whenever "users" changes, Angular will notice (since that scope property (i.e., "users") is bound (one-way data binding) to the ng-repeat directive), and Angular will update the view.

How to update properties of an array of beans while iterating in jspx

The model returns a list of beans which are displayed in a table using <c:forEach tag>. Some properties are of type input, so the user can edit these inline (optional).
The question is how to set a corresponding beanObject[by row index] when user clicks on checkbox? If clicked, then the appropriate bean needs to be updated via AJAX, I think.
So, how can we do that?
Normal Master-Detail approach has way too many clicks, that is why I need "update-able" tables.
Controller:
return new ModelAndView("daily","daily", dailyListOfBeansRecords;
Jspx:
form submit...
...
<c:forEach var="week" items="${Daily}" varStatus="loopIteratorValue">
<tr class="${loopIteratorValue.index % 2 == 0 ? 'd4' : 'd3'}">
<td><checkbox id="present" onchange="ProcessedUpdated(this,${loopIteratorValue.index})" value="${week.processed}"/></td>
</tr>
</c:forEach>
It seems to me you totally misunderstand jsp. jsp(x) is executed on the server side. you need javascript to do client-side processing.

Resources