I am trying to display a JSON response in a table using ng-repeat. The problem is that not all objects recieved are the same. All of them have a date, short message and long message. There are also ones with an additional value list, differing in length. This list should be diplayed underneath the long message within its own table or list. I use the alert.slice().reverse() because I want the newest entries to be on top. The new objects are inserted using .push({values}).
<tbody class="AlTbody" ng-repeat="alerts in alerts.slice().reverse()" ng-class="className">
<tr class="Altr Aldate">
<td ng-show="{{alerts.Date}}"><b>{{alerts.Date}}:</b>
</td>
</tr>
<tr class="Altr Alshort " ng-click="toggleDetail($index)">
<td>{{alerts.S}}</td>
</tr>
<tr class="Altr " ng-show="activePosition == $index">
<td class="msgL">{{alerts.L}}
<!-- 1) <p ng-show="{{item.List}}"><br><ul><li>Previous values:</li> <li ng-repeat="vals in ValueList">{{vals.value}}</li></ul> </p>-->
<!-- 2) <p ng-show="{{List.txt}}"> <br><ul><li>Previous values:</li> <li ng-repeat="List in alerts.List">{{List.txt}}</li></ul> </p>-->
</td>
</tr>
</tbody>
I already tried two approaches as seen in the code. The first one displayed the list correct however it was displayed underneath every long message instead of only the one it belongs to. I used a new variable.
var l=valList.length;
scope.List=true;
while(l>-1){
scope.ValueList.push({value: valList[l]});
l--;
}
The second approach did not work at all because I could not find an index.
var l=valList.length;
var indexV= jQuery.inArray(currdate,scope.alerts.Date);
while(l>-1){
scope.alerts[indexV].List.push({txt: valList[l]});
l--;
}
edit:
This is the current output. There you can see two objects( date, short message and long message) and both of them have the previous values section. However only the upper object is supposed to diplay the list of previous values.
What you are trying to achieve is entirely possible, my advice is to start at a known point and work from there.
I have put together a jsfiddle to show you how nested ng-repeats will work. try and work from that point. As a side note it looks like your JSON structure is overly complex, if you can simplify that down I would.
https://jsfiddle.net/roscorcoran/wyu7tgxm/
<div ng-app="App" ng-controller="Ctrl1">
<div ng-repeat="alert in alerts">
<a ng-if="alert.Date">{{alert.Date}}</a>
<p ng-repeat="val in alert.L.vals">
<a ng-if="val && val.value">{{val.value}}</a>
</p>
<p ng-repeat="item in alert.List">
<a ng-if="item && item.txt">{{item.txt}}</a>
</p>
</div>
</div>
You can try to add a ng-if statement inside the ng-repeat loop:
<p ng-if="{{values.list}}"><br><ul><li>Previous values:</li> <li ng-repeat="vals in values.list">{{vals.value}}</li></ul> </p>-->
Okay so this works for me now. It still always displays "Previous Values:" but the values only display when they actually belong to the message.
<ul ng-if="alerts.List.vals"><li>Previous values:</li> <li ng-repeat="val in alerts.List.vals" >{{val.value}}</li></ul>
This might not be the best and most elegant solution but it works.
if(valList){
scope.alerts.push({Date:currdate,S:msgSn,L:msgLn, List:{ vals:[{value:valList[0]},{value:valList[2]},{value:valList[4]},{value:valList[6]}] } });
}else{
scope.alerts.push({Date:currdate,S:msgSn,L:msgLn });
}
I only display the even indexes of the value array because the list of values was a string which I split and every uneven entry is "):" which I don't need to display.
Related
How do I make AngularJS render table columns correctly before the intended content for them is received?
I'm using ng-if to show the content, since I need different elements depending on the value that I get back from an API call, see below. This is the only reason for not using ng-bind, which I assume would be a more legitimate solution.
<td ng-if="someArray.length > 0"><a ng-href="someLink">Yes</a></td>
<td ng-if="someArray.length == 0">No</td>
Using this, due to obvious reasons the particular column is not shown at all while someArray is not initiated. I could check for undefined in the second ng-if, but I would rather have the column be completely empty while waiting for a value.
I am still quite new to AngularJS and I assume that there is a best-practice here.
You can use ng-if in internal dom elements
<td>
<a ng-if="someArray.length > 0" ng-href="someLink">Yes</a>
<p ng-if="someArray.length == 0">NO</p>
</td>
You can move the ng-if into the elements within the td:
<td>
<a ng-if="someArray.length > 0" ng-href="someLink">Yes</a>
<span ng-if="someArray.length == 0">No</span>
</td>
Please check this:
http://plnkr.co/edit/61JgnU?p=preview
If you start filling the fields you will see the fields been printed. Which is fine.
Now if you press the Add Input then bunch of fields will be added.
I need to add the newly added fields value to be printed under the main fields. (Please let me know if you need more explanation.)
Here is how I need it to be for the newly added fields:
I don't know how to show the fields without needing to make another $scope.fields array.
One more thing, in the $socpe.fields array there are more than 20 different fields, I just put what it needed for this question.
Thanks.
My recommendation would be to loop through your inputs array with the same markup you used for the users. The following seems to work if I understand what you're looking for.
<div ng-repeat="input in inputs">
<table class="table table-bordered">
<tr ng-repeat="field in fields | orderBy: 'index'" ng-show="input[field.id]">
<td class="col-md-4"><b>{{field.name}}</b>
</td>
<td class="col-md-7">{{input[field.id]}}</td>
</tr>
</table>
</div>
Another option you might want to consider is a custom directive taking the fields array and the display array as parameters.
I am new to angularJS i have an object of which contains nearly 4000 records which i am showing them using ng-repeat
<div infinite-scroll='loadMore()' infinite-scroll-distance='2'>
<li ng-repeat="outlet in outlets | filter:searchText" >
<table>
<tr>
<td>
<div clss="title">{{outlet.name}}</div>
<div class="discription">{{outlet.address}},{{outlet.cityName}},{{outlet.countyName}}</div>
</td>
</tr>
</table>
</li>
</div>
now i wanted to use endless list by using ng-infinitescroll but the problem is the filter is happening only which are visible not in total 4000 records so what do i have to implement to get the search functionality to be done in total 4000 records and endless list
searchText filter would only work on in-memory data. In order to search things that havent been loaded yet you would need to implement a server-side search api.
I have a simple View Model that has the traditional one-to-many relationship: Customers have Orders.
I'm creating a table such that each line has a Customer name with a line of Orders following it. It's all working great, but unfortunately few Customers have the same amount of orders, so building the table ends up looking like a sideways bar chart.
I know there is a standard solution to this, but I can't for the life of me figure it out. What I'm going for is to have every row contain the same amount of cells. I've considered putting dummy data into my model, but that just smells bad. I can get the maximum amount of orders possible, but I can't seem to figure out how to design a template that can use any of that information to create uniform tables. Here's what I have so far:
//#data is my ViewModel containing a few other things
<table id="ordersTable">
<!--header stuff-->
<tbody>
{{for #data.Customers tmpl='tmplRow' /}}
</tbody>
// OrderRow.tmpl.html
{{if #index % 2 == 0}}
<tr class="tableRowAlt1">
{{else}}
<tr class="tableRowAlt2">
{{/if}}
<td>{{>Name}}</td>
<td></td>
{{for Orders }}
<td>
{{>OrderId}}
</td>
{{/for}}
</tr>
EDIT: So I've decided to just force the numbe of columns, but now I'm getting some strange behavior on my new template:
// OrderRow.tmpl.html
{{if #index % 2 == 0}}
<tr class="tableRowAlt1">
{{else}}
<tr class="tableRowAlt2">
{{/if}}
<td>{{>Name}}</td>
<td>
{{>Order[0].Id}}
</td>
<td>
{{>Order[1].Id}}
</td>
<!--...-->
</tr>
It's rendering "Order.0 is null or not an object." I've verified that every row has data in it, but yet the template thinks it does not. I imagine this has something to do with the fact that I'm looking for array elements, but I'm not sure how to go about accessing the elements by index in a way that jsRender will accept.
This may not qualify as an answer but its too long as a comment.
I don't 100% follow what you want. I'm guessing that if you have 5 customers and one customer has 10 orders and the 4 other customers have 7 orders, then you want 3 empty td tags for the other 4 customers each.
The first thing you need to know is the length of the longest order list. Lets say its 10. You then need to pass that into the OrderRow template. Actually, you need the difference between the max and the number of orders of the current customer. Lets call that delta.
Now, after the {{for Orders}} loop, you have two choices. You can either add a single td with a span of delta or you can add delta number of empty td tags. You want to do either of these additions only if delta is greater than 0. Assuming ~max is passed in as the maximum number of orders than something like:
{{if (~max - Orders.lengh) > 0 }}
<td colspan='{{ ~max - Orders.length }}'></td>
{{/if}}
What I'm confused about is the end result is going to look the same. It will still have the orders as a sideways bar chart on the left hand side of the table.
You mentioned "a standard solution to this". Can you point to a rendered example somewhere?
My HTML
<tr class="g1">
<td id="saveursqte_box[]">
<div class="t">
xxxxxxxxxxxxx
<div class="r">
<div class="a">
</div>
<img src="images/saveurs/saveur_test.jpg" width="125" border=0>
</div>
</div>
</td>
<td class="i">
<input type="text" name="saveursqte[]" alt="2.95" value="" size="3" onBlur="__sumform();">
</td>
</tr>
What I'm trying to do
I want to get the contents of: <td id="saveursqte_box[]"> using javascript.
which is:
<div class="t">
xxxxxxxxxxxxx
<div class="r">
<div class="a">
</div>
<img src="images/saveurs/saveur_test.jpg" width="125" border=0>
</div>
</div>
I tried this javascript:
var saveursqte_box = document.getElementsById('saveursqte_box[]');
and then
htmltotal = htmltotal + saveursqte_box[i].innerHTML;
but javascript doesn't seem to like me :-(
It is document.getElementById no "s".
This document.getElementById('saveursqte_box[]'); returns a single dom element not an array like jQuery.So the code to get the innerHTML would be:
htmltotal += saveursqte_box.innerHTML;
In addition to #scrappedcola's note about there being no 's' in getElementById, you may also be having problems using square brackets in the element id.
I ran your example in Firefox 4 with <td id="saveursqte_box"> and it worked, whereas using <td id="saveursqte_box[]"> I got NULL as the result of getElementById().
Also:
saveursqte_box[i]
i is not defined. Just use saveursqte_box
Thanks to all! I know my Javascript skills are low but by combining your answers together I came with this and it works perfectly :
htmltotal += document.getElementById('saveurmoisqte_box_' + i).innerHTML;
As per your answer, I removed the "s" of getElementById. My bad: I copied getElementsByName and then replaced the Name by Id... This is why there was a "s" there. The kind of mistake that can waste you a week to debug...
After that, I rename my <td id="extrasqte_box[]"> with <td id="extrasqte_box_0">. I thought you could write ids arrays like you do with names (ex: name="xxxx[]") and then iterate but I was wrong.
With that in place it works perfectly! Not bea-u-tiful but it works.
What I'm actually doing with this is:
I have an order form with many items and when you fill an input (quantity), an hover image of the product appears to its right... and when you move away (onBLur), the form total is updated, AND using the function here above, I get the content of the <td> (including the hover image) and put a summary of the items chosen in the "checkout section". The result is super-clean for the user and user-friendly. The inconvenient is I hope this makes sense to you.