Ng-switch in ng-repeat issue - javascript

I have an odd issue that is driving me crazy
I basically have a list of article of different type: news, tweets and video
I am rendering them like this:
<div ng-repeat="item in items | orderBy:-timestamp track by item.id" ng-switch="item.type">
<?php
include("templates/ang-youtube.html");
include("templates/ang-tweet.html");
include("templates/ang-news.html");
?>
</div>
Inside each include i am doing something like this:
<div class="item" masonry-brick ng-switch-when="news">
...content in here
</div>
or
<div class="item" masonry-brick ng-switch-when="tweet">
...content in here
</div>
or
<div class="item" masonry-brick ng-switch-when="youtube">
...content in here
</div>
Now the problem is the youtube items are always rendered first. The order of the items (timestamp) is ignored. The tweets and news items though render correctly.
If i remove the switch and just list out the items as text then everything is in the correct order. As soon as I add the switch the youtube items are rendered first again.
Any ideas what I am doing wrong?
I have tried moving the switch inside the ng-repeater like so:
<div ng-repeat="item in items | orderBy:-timestamp track by item.id">
<div ng-switch="item.type">
<?php
include("templates/ang-youtube.html");
include("templates/ang-tweet.html");
include("templates/ang-news.html");
?>
</div>
</div>
But it makes no difference. The youtube items are always rendered first.
If i inspect the $scope.items array they are ordered correctly by timestamp.
I have also tried using an ng-if instead of a switch but get the same outcome
Any ideas? :-(
Also tried using ng-include like this:
<div ng-include="'templates/ang-{{item.type}}.html'"></div>
But that doesn't work

DOH!!! Needed to add the preserve order attribute as outlined here
https://github.com/passy/angular-masonry

Related

Angular Dragula and ng-repeat $index

I have an ng-repeat of rows. I set them up so you can reorder them with drag-and-drop using Angular Dragula. This works fine, but the ng-repeat $index remains the initial value for each item after dragging. See screen captures below before and after a drag of the "Recipient" row.
Is there a way to update the index? I also want to re-order the menu with javascript, with that button in each row, but for that to work I need to get the current $index (and decrement/increment it) and that won't work if the index is incorrect like this.
Before Drag
After Drag
For what it's worth, this is the answer:
<div class="table-cards-body" dragula="'first-bag'" dragula-model="home.quickReceiveFields">
<div class="table-cards-row drag-item" ng-repeat="field in home.quickReceiveFields track by $index">
<div class="one">{{field.name}}</div>
<div class="two">{{field.type}}</div>
<div class="three">{{field.default}} {{$index}}</div>
<div class="four"><input type="checkbox" ng-model="field.display"></div>
<div class="five"><input type="checkbox" ng-model="field.retain"></div>
<button class="btn btn-default btn-xs" ng-click="home.moveItemUp($index)">^</button>
</div>
</div>
Despite what the docs say on the angular-dragula site, you need to put the dragula-model attribute on the container into which you put the repeating items. Not the ng-repeat itself.
Try to add in ng-repeat track by $index.

How can I have arbitrary content inside an ng-repeat with Angular?

I have an ordered list of items that I want to be displayed. Getting this done with Angular is trivial:
<p>Filter a game: <input type="text" ng-model="search.name" /></p>
<game-card ng-repeat="game in games | filter:search" game ="game" size="large"></game-card>
This outputs an ordered list of games that has been sorted from the database. However, I want to show a few snippets of arbitrary content inside this ng-repeat. This diagram below indicates what I'm after. The lefthand side shows how it should look in the unfiltered state, the righthand side if a search term as present.
As you can see, I want to highlight the first item with a "Next up" heading, and following that, an "After that" heading. When a search is present, I don't want these headings at all as they won't be relevant.
I'm completely new to Angular ("you lost me at service" new, by the way), but have come from a Knockout.js background. What is the "Angular way" of solving this?
Stack up ng-if's on the headings and compare with $index? Does $index even care about the filter being applied?
Kind of dirty solution: within the ng-repeated element, put something like
<div ng-if="$index === 0">
<h2>Next up</h2>
</div>
<div ng-if="$index === 1">
<h2>After that</h2>
</div>
<div>
<!-- Your content goes here, unconditionally -->
</div>
And the obvious problem with this is that two tests are performed for each "instantiation" of the content of the ng-repeated element, and they are useless except for the first and second.
Otherwise you could place your first two bits of contents with headers outside the ng-repeat and then start repeating from index 2, but I'm not sure that's possible with ng-repeat.
If it's not, then split your data into firstElement, secondElement and rest where rest is Array.prototype.slice.call(/* your initial list of elements */, 2).
The problem with this last solution is that it requires you to adapt your data to how you present it, which is undesirable for obvious reasons.
edit: OK here's something better, not tested:
<div ng-if="elements.length > 0">
<h2>Next up</h2>
<div><!-- First content goes here, it uses elements[0] --></div>
</div>
<div ng-if="elements.length > 1">
<h2>After that</h2>
<div><!-- Second content goes here, it uses elements[1] --></div>
</div>
<div ng-repeat="element in elements.slice(2)">
<!-- The rest goes here, unconditionally -->
</div>
Instead of doing your ng-repeat in the game-card tag, do it in a wrapping div and then use ng-repeat special variables:
<p>Filter a game: <input type="text" ng-model="search.name" /></p>
<div ng-repeat="game in games | filter:search">
<div ng-if="$first">NEXT UP</div>
<div ng-if="$index === 1">AFTER THAT</div>
<game-card game="game" size="large"></game-card>
</div>
My solution was to ng-show the titles only if the length of the results passed through the filter equaled the total number of games:
<h2 ng-show="games.indexOf(game) == 1 && search.length == games.length">More Games</h2>

How to repeat elements pulled from an array inside a javascript object literal with ng-repeat

I'm repeating elements from a big javascript object literal. Currently, I display the tabbed navigation, image, and title for each product correctly. I cannot get the info to display correctly however. I have the following code:
<div ng-repeat="section in tab.sections" class="product">
<div ng-repeat="child in section.children" ng-if="productIsActive(child, $index)">
<div class="additionalProductInfo">
<nav class="secondaryTabbedNavigation">
<ul>
<li class="active" ng-repeat="pTabs in child.productTabs">
<a class="activelink" href="#">{{pTabs.title}}</a> //title of each tab
</li>
</ul>
</nav>
</div>
<div class="productImage">
<img ng-src="{{ child.productImageURL }}"/> //the product image
</div>
<div class="productInfo">
<h2 class="productTitle">{{ child.title}}</h2> //the product title
<div ng-repeat="info in pTabs.infoData" class="productDescription">
<p>
{{info[1]}} //product info goes here.
</p>
</div>
</div>
</div>
</div>
I also tried "{{info}}" , "{{info[i][i]}}", and a couple things using $index. But when "{{info}}" didn't display anything, I figured I was retrieving the data incorrectly.
Here is the "tabs" javascript object that all this info comes from:
As you can see the product info is in a two dimensional array (the first array with the labels of what the information is (e.g. "Title", "Link") and the corresponding information is in the second array. I know this may not be ideal, but this information is currently grabbed from .csv files that prone to changing
and I cannot change how they come into this javascript object.
I know this may seem overcomplicated but this is about as deep as I need to go to get data from the large javascript object and I'm very close.
How can I get the contents from the second array in the two dimensional array (infoData[1]) to display like I did with the tabs, image, and title.
Thank you very much for your time!

Angular.js ng-repeat inside ng-repeat

I'm trying to repeat an array of objects and an array of images. I would like each one image to be repeated with each object. My problem is if I nest the ng-repeat inside another ng-repeat, it repeats all the images every time. My code is below. I hope this makes sense. Thanks.
<div class="feed-content">
<div ng-repeat="feed in feeds | filter:filterText" class="article animate-repeat">
<h3>{{feed.title}}</h3>
{{feed.content | limitTo:100}}<br/><span class="read-more">Read More</span>
</div>
<div ng-repeat="img in imgs" class="article-image" style="background-image: url('{{img}}');"></div>
</div>
It's because your second loop is outside the parent loop, also you might want to use imgs field from each feed object in the parent loop, so you're probably need something like ng-repeat="img in feed.imgs"
All in all you're looking for something like this structure
<div ng-repeat="feed in feeds">
<h3>{{feed.title}}</h3>...
<div ng-repeat="img in feed.imgs">...</div>
</div>

Output a Laravel variable within a javascript template

I am working on a Laravel-4 application and I am using javascript templates to render items on a particular page. Below is my template for my slideshow items
<script type="t/template" id="bookItem">
<div class="resource-wrap" data-resource="#{{=type}}">
<div class="resource #{{=type}}">
#{{id}}
<div class="image">
#foreach($slideshow->find($slideshow->id)->slides()->take(1)->get() as $slide)
<img width="100%" height="100%" src="/img/slideshows/{{$slide->link}}"/>
#endforeach
</div>
#{{/id}}
<ul class="info">
<li class="title">#{{=id}}#{{=title}}#{{=name}}</li>
<li>#{{=desc}}</li>
</ul>
<a class="ov open-#{{=type}}" href="#"></a>
</div>
</div>
</script>
It is rendering alright on the page and everything is working correctly except for one thing. This line:
#foreach($slideshow->find($slideshow->id)->slides()->take(1)->get() as $slide)
I am trying to pass in the id of the current item but cannot seem to do so. I can here:
<li class="title">#{{=id}}#{{=title}}#{{=name}}</li>
But when I use #{{=id}} in my loop I get an error. I am wondering how I can print this variable out in the loop?
I tend to try to avoid querying in the view and query within the controller, passing the collection to the view - makes it cleaner in the view. Keep the view separate as much as possible
So assuming you have passed a variable $slideshow which is your collection you can then do:
<div class="image">
#foreach($slideshow AS $slide)
<img width="100%" height="100%" src="/img/slideshows/{{$slide->link}}"/>
#endforeach
</div>
I'm not clear what value $id relates to in your question. Is that the id of the slide? if it is then as long as it's contained in the loop you can get that by $slide->id
If assumption is wrong can you confirm what id relates to

Categories

Resources