Is it possible in AngularJS, while in a nested ng-repeat, to access data from a third table?
Here's an example... let's say I want to create a table which lists actors and actresses in the first row, and then the first column would list movies. In the cells where actor and movie intersect, we might display a rating for how well that actor performed in that film. However, since only a few actors may appear in each film, more often than not those intersecting cells would be blank. If we have roughly 120 actors and 600 films, then we're talking about 72,000 possible intersections, although our dataset may only actually have about 5000 entries.
I'm using three JSON files to do this; actors.json, movies.json, and ratings.json. The first two files contain lists of the actors or movies, and extended data for each; ie: year, genre, director, or age, nationality, etc. The last file; ratings.json, contains simply the ID of the movie, the name of the actor (our data doesn't contain IDs for the actors), and the rating.
Setting up my table, in the first row I ng-repeat through the actors file to display my header row, with the names and information about each actor. I skip the first cell, as it's the top of my header column.
Next, I ng-repeat through my movies data, opening a new row for each, and then within each row, I ng-repeat through my actors data again to create the ratings td's themselves.
All of this is working, but this is where I go off the rails. I cannot figure out an efficient way to grab the ratings data easily. I did figure out HOW to make it work, by basically looping through the entire ratings table, and filtering for a match, but I know that can't be the right way to do it.
Here's some sample code:
<table>
<tr>
<td></td>
<td ng-repeat="movie in movies>
<p>{{movie.name}}</p>
<p>{{movie.year}}</p>
</td>
</tr>
<tr ng-repeat="actor in actors>
<td>{{actor.name}}</td>
<td ng-repeat="movie in movies">
<span ng-repeat="rating in ratings | filter: { id: movie.id } : true | filter: { actor: actor.name } : true">
{{rating.rating}}
</span>
</td>
</tr>
</table>
As you can imagine, this method is really (REALLY) slow.
If this were php or something, I'd just grab the data from an array (ie: $rating[$movie_id][$actor_name]), simple as pie, but for the life of me I can't figure out how to do this with AngularJS, not at all. I just want to reference the proper bit of ratings data directly.
As requested, here's a sample of ratings.json.
[
{
actor: "Brad Pitt",
id: "13",
rating: "3"
},
{
actor: "Jennifer Anniston",
id: "8",
rating: "7"
},
...
]
Thanks,
m.
You would need to pre-process your ratings.json array into a nested hash.
var ratings = {};
for (var i=0; i < ratingsArray.length; i++){
var ratingEntry = ratingsArray[i];
var id = ratingEntry.Id, actor = ratingEntry.actor;
rating[id] = rating[id] || {};
rating[id][actor] = ratingEntry.rating;
}
Then you could just do exactly what you would expect had it been PHP:
<tr ng-repeat="actor in actors>
<td>{{actor.name}}</td>
<td ng-repeat="movie_id in movies">
{{rating[movie_id][actor]}}
</td>
</tr>
Related
I currently have an ask to provide a "Lookup Table Management" interface to super users of an app I'm working on. They want to make changes to lookup tables that are used throughout the app (they won't be able to change IDs, of course).
I'd like to come up with a way to generically handle this without having to create a form for each LUT. Or if there is a plugin I don't know about that would be even better
All the LUTS are vastly different from each other in terms of fields. I'm trying to write a loop to loop through all the fields of a LUT object and then spit out the values for each object of that LUT.
Example:
DrinksLut
String name
Double price
Integer numSold
PetsLut
String name
Integer age
String breed
String size
Boolean fixed
I'm trying to provide a table output that lists the field properties as headers as well as the individual object values for rows depending on the LUT they choose to edit (Pets, Drinks, etc.)
Current Code
def resultList() {
def selectedLut = grailsApplication.getClassForName(params.lutFilter?.replace('class ', ''))
/* get field names, types and a "user friendly" name to use in the table header */
def objProps = new DefaultGrailsDomainClass(selectedLut)?.persistentProperties.collect {
[
name: it.name,
type: it.type,
friendlyName: Helper.splitCamelCase(it.name)
]
}
/* get all rows for the chosen LUT */
def results = selectedLut.getAll()
render(template: '../lookupTable/resultList', model:[results: results, objProps: objProps])
}
...
<table id="lutTable" class="col-xs-12">
<thead>
<tr>
<g:each in="${objProps}">
<th>${it.friendlyName}</th>
</g:each>
</tr>
</thead>
<tbody>
<g:each in="${results}">
<tr>
<td>${it}</td> <!-- this currently is the object of a LUT and I need to get each of its field properties and values to spit out here -->
</tr>
</g:each>
</tbody>
</table>
I'd greatly appreciate any assistance or ideas! The app s using Grails 2.5.5
I am using angular js to sort json data. everything is working fine but the part where empty or json with null data shows up right at top. Anyone has an example that pushes both empty and null data to bottom .
Example
{itemId: 42608125,
parentItemId: 42608125,
name: "Apple iPod touch 32GB, Assorted Colors",
salePrice: 237.49,
upc: "888462353151"
},
{itemId: 39875894,
parentItemId: 39875894,
name: "Griffin Survivor Extreme-Duty Case for Apple iPod touch 5G, Blue",
msrp: 29.88,
salePrice: 22.64
}
As you can see here one has msrp and other does not . SO when I order by msrp I see the one not having anything set at top.
<tr ng-repeat="u in ctrl.recommededResults | orderBy:'-productReview.reviewStatistics.averageOverallRating'">
<td><span ng-bind="u.itemId"></span></td>
<td><span ng-bind="u.name"></span></td>
<td><span ng-bind="u.msrp"></span></td>
<td><span ng-bind="u.productReview.reviewStatistics.averageOverallRating"></span></td>
</tr>
I believe you need to use a custom function to define how to order by.
Without any examples, it's hard to provide the code you need.
See examples in this SO post:
Custom sort function in ng-repeat
I am using xml2json to translate a xml file from medline. I am stuck on using ng-repeat to display the information I need. I need to display the title,url and see-reference. When i have one health-topic in the xml file The title and url display fine. When I add more health-topics it does not work. any help is appreciated, thanks
plunkr
<table>
<tr ng-repeat="topic in topics">
<td>{{topic._title}}</td>
<td>{{topic._url}}</td>
<td>{{topic.see-reference}}</td>
</tr>
</table>
<pre>{{topics | json}}</pre>
The structure of your XML is like this:
<health-topics total="1909" date-generated="01/03/2015 02:30:35">
<health-topic title="Abdominal Pain">
</health-topic>
<health-topic title="Abdominal Pain">
</health-topic>
<health-topic title="Abdominal Pain">
</health-topic>
xml2json creates an object for every element. The properties of the object are the element's attributes (starting with an underscore) and the child elements. In your case:
//health-topics
{
_total: "1909",
_date-generated: "01/03/2015 02:30:35",
health-topic: [
{
_title: Abdominal Pain"
...
health-topic is an array containing the topics. If you have a single topic wrapped with health-topics it would be:
//health-topics
{
_total: "1909",
_date-generated: "01/03/2015 02:30:35",
health-topic: {
_title: Abdominal Pain"
...
health-topic is now an object. But maybe a single topic wouldn't even be wrapped with a health-topics element. That's something only you know.
All in all the data structure is different depending on the number of topics. You would need to check and adapt to that. The code working for multiple topics would be
$scope.topics = $scope.dom['health-topics']['health-topic']
I am building my first app. It is an ordering system where a customer can add items to the cart. Everything is working well. However, my client would like a way to alert the customer if they try to add a quantity to the cart that is greater than the current stock.
My client doesn't want to show stock levels, unless the customer adds something greater than the stock available.
I have a table with stock items in each row. I'd like to do three things, if the stock level is greater that available stock, I'd like to change:
• Class on the table row
• Add class disabled to the submit
• Show a div that has the available stock in.
To make matters a little more interesting, customers have to order by packs and not individual items.
Basically, I am trying to get the following code to work:
This is the general markup:
<tr ng-repeat="series_detail in productDetail | filter:filter">
<td>{{series_detail.sku}}</td>
<td>{{series_detail.size}}</td>
<td>{{series_detail.price</td>
<td>{{series_detail.pack}}</td>
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
<td><span class="itemtotal">{{series_detail.price * qty | number:2}}</span></td>
<td class="form-inline" style="text-align:right;">
<input type="submit" class="add_to_cart_submit btn btn-danger btn-small" value="Add">
</td>
</tr>
I want to then show this div
<div ng-show="'{{totalitems}}' > '{{series_detail.stock}}'">Yo, no stock dude</div>
I have tried adding a model, 'totalitems' to a row and then using ngShow to pop it up. However, it seems that 'totalitems' is evaluating to nothing. I've experimented with a few other options, but nothing has worked (ngIF etc.).
Regarding the changing of class, I am guessing, that once I get this sorted, I can transfer the expression to ngClass? I have played with this, and again, nothing has worked so far.
Provided this line goes inside the ng-repeat:
<div ng-show="qty * series_detail.pack > series_detail.stock">Yo, no stock dude</div>
For the class indication, lets say on tr, you could use the same expression as:
<tr ng-class="{outOfStock: (qty * series_detail.pack > series_detail.stock)}" ng-repeat="series_detail in productDetail | filter:filter">
outOfStock is class in your CSS.
BTW,
<td ng-model="totalitems" ng-init="0">{{qty * series_detail.pack | number}}</td>
does not set totalitems to whatever {{qty * series_detail.pack | number}} evaluates to.
If you really need totalItems in your model a possible option is to have a method on the series_detail instance
objRef.totalItems = function(qty) {
return qty * this.pack;
}
and use it as:
<div ng-show="series_detail.totalItems(qty) > series_detail.stock">Yo, no stock dude</div>
<td>{{series_detail.totalItems(qty) | number}}</td>
I am not to sure to understand everything but something like this should works ?
<div ng-show="isStockAddedGreaterThanAvailable()">{{series_detail.stock}} Yo, no stock dude </div>
And in your controller
$scope.isStockAddedGreaterThanAvailable = function(){
....
}
bit of a newbie to mvc. i am having trouble with the following scenario:
I have a view with the following:
<tr>
<% foreach (var game in (IEnumerable<Game>)ViewData["Game"])
{ %>
<td>
<input type="checkbox" name="selectedObjects" value="<%=game.Id%>" />
</td>
<td>
<%=game.GMTDateTime%>
</td>
<td>
<%=game.HomeTeamId%>
</td>
<td>
<%=game.AwayTeamId%>
</td>
<td>
<%=game.Venue%>
</td>
</tr>
All of the data displays OK except for HomeId and AwayId. These two fields are linked to another table called team and each Id in HomeTeamId and AwayTeamId relate to a record in the Team table and each id has a "Name". My problem is how do I display the "Name" from the Team table rather than the Id field shown.
The controller shows:
ViewData["Game"] = dc.Games.GetGames();
The query I am using in linq is:
public static IEnumerable<Game> GetGames(this Table<Game> source)
{
return from c in source
orderby c.GMTDateTime
select c;
}
Assuming you have defined the relationships in your schema, this should work:
<td>
<%=game.Team.Name%>
</td>
<td>
<%=game.Team1.Name%>
</td>
Because there are multiple FKs to the Team table, you will see two properties for Team, Team and Team1 (or similar). You'll need to determine which is which by looking at the generated LINQ code, or by trial and error, i.e., observing the output.
Normally using partial classes I will make additional properties that expose the Team object(s) with better names that make it clear which FK they are for.