Automatically load a view from the controller after a timer in AngularJS - angularjs

Basically, what I am attempting to do is create a Slideshow. The reason why I am using Angular for this is to get the benifits from templating and hopefully load only one template to the page at a time.
I have my data in a JSON file which the controller gets:
JSON:
{
"prop_title" : "Hyde Lane, Hyde",
"prop_postcode" : "SP2 7AP",
"prop_price" : "",
"prop_image" : "",
"prop_desc" : "",
"template" : "views/prop-thumbs.html",
"info_image" : "",
"duration" : "4000"
},
Controller:
function AppCtrl($scope, $http) {
//GET THE JSON FILE
$http.get('json/pages.json').success(function (data) {
//ASSIGN THE PAGES TO THE SCOPE
$scope.pages = data;
//LOOP THROUGH THE DATA AND ASSIGN THE VIEW
for (var i = $scope.pages.length - 1; i >= 0; i--) {
};
});
}
As you can see from my JSON file, each element contains the view file to use, and the duration that it needs to stay on screen for. Also, as you can see in my controller, I have begun creating a for loop that will hopefully contain my code that will assign view on a timer. Is this possible? Whats the easiest and best way to do this?
Any help seriously appreciated, I have pretty tried everything now!

as Mark Rajcok pointed in the comments, you will probably need to use a $timeout
Here is what I would have done : http://jsfiddle.net/DotDotDot/zbg57/
The html part is quite simple, I just tell angular to include what is in the whatToInclude variable :
<div ng-include='whatToInclude'></div>
On the controller side, I initialize the data with a template and a counter, then I define a nextSlide function, which will call the next template with the timeout passed in parameter. I call this function to start the loop with the initials parameter (0s timeout, first element of the data)
$scope.whatToInclude='tpl1.html';
$scope.count=0;
$scope.nextSlide=function(timeOut){
$timeout(function(){
$scope.whatToInclude=$scope.data[$scope.count].template
$scope.count+=1
if($scope.count>=$scope.data.length)
$scope.count=0
$scope.nextSlide($scope.data[$scope.count].duration)
},timeOut);
};
$scope.nextSlide(0)
I think this can be a good start for a slideshow ;)
Have fun

I made a tutorial with a similar goal in mind:
https://www.youtube.com/watch?v=9COtsDovNpM
Basically store the views in an array of some sort and then based on a variable display that template. Angular will not load the template until ng-show='true' so they won't load all at once but as their clicked or cycled through.
Code example from my tutorial.
Replace ng-switch with whatever works for you.
The common premise is "show this template when that is equal to true".
<div class="tabbable tabs-left">
<ul class="nav nav-tabs">
<li ng-class="{active: main.active.tab == 'info'}">
<a ng-click='main.active.tab = "info"'>Settings</a>
</li>
<li ng-class="{active: main.active.tab == 'categories'}">
<a ng-click='main.active.tab = "categories"'>Categories</a>
</li>
<li ng-class="{active: main.active.tab == 'pages'}">
<a ng-click='main.active.tab = "pages"'>Pages</a>
</li>
<li ng-class="{active: main.active.tab == 'locations'}">
<a ng-click='main.active.tab = "locations"; main.locationgroup = {}'>Locations</a>
</li>
<li ng-class="{active: main.active.tab == 'experts'}">
<a ng-click='main.active.tab = "experts";'>Experts</a>
</li>
<li ng-class="{active: main.active.tab == 'resources'}">
<a ng-click='main.active.tab = "resources"'>Resources</a>
</li>
</ul>
<div class="tab-content">
<div ng-switch='main.active.tab'>
<div
ng-switch-when='info'
ng-include='"/apps/series/views/tabs/info.html"'></div>
<div
ng-switch-when='categories'
ng-include='"/apps/series/views/tabs/categories.html"'></div>
<div
ng-switch-when='pages'
ng-include='"/apps/series/views/tabs/pages.html"'></div>
<div
ng-switch-when='locations'
ng-include='"/apps/series/views/tabs/locations.html"'></div>
<div
ng-switch-when='experts'
ng-include='"/apps/series/views/tabs/experts.html"'></div>
<div
ng-switch-when='resources'
ng-include='"/apps/series/views/tabs/resources.html"'></div>
</div>
</div>
</div>

Related

How to add a particular class to the elements repeated using ng-repeat?

I have been using ng-repeat for adding repeated list items in my code. But, I am not getting how to add a class to just one of the elements.
I am looking for something like this.
<div class="events-wrapper">
<div class="events">
<ol>
<li>21</li>
<li>22</li>
<li>23</li>
<li>24</li>
<li>25</li>
<li>26</li>
<li>27</li>
<li>28</li>
<li>29</li>
<li>30</li>
<li>31</li>
<li>32</li>
<li>33</li>
<li>34</li>
<li>35</li>
<li>36</li>
<li>37</li>
<li>38</li>
<li>39</li>
<li>40</li>
<li>41</li>
<li>42</li>
<li>43</li>
<li>44</li>
</ol>
<span class="filling-line" aria-hidden="true"></span>
</div>
<!-- .events -->
</div>
<!-- .events-wrapper -->
I have done this:
<div class="events-wrapper">
<div class="events">
<ol>
<li ng-repeat = "dt in time">
{{dt.dc}}
</li>
</ol>
<span class="filling-line" aria-hidden="true"></span>
</div>
<!-- .events -->
The accompanying js is
var app = angular.module('timelineApp', [])
app.controller('tryCtrl', function ( $scope, $http ) {
$http({
method: 'get',
url: '../json/timeline.json'
}).then(function (response) {
$scope.time = response.data.timeline;
})
})
The elements properly repeat. But, I want to initialize this by adding the selected class to the first element?
You can use the ng-class directive in combination with ng-repeat's $first attribute to set a class selected only for the first element that is produced by the repetition.
<li ng-repeat="dt in time" ng-class='{selected:$first}'>
{{dt.dc}}
</li>
$first is a special property that is automatically exposed on the local scope when you use ng-repeat.
If you want multiple selections from an array, use $index:
<li ng-repeat="dt in time" ng-class='{selected: itemSelected[$index]}'>
{{dt.dc}}
</li>

How to implement the Bootstrap pills active class with Angular

I want to create a set of pills with all the states with their number of electors and I want the pill that is clicked becomes active. So, my unsuccesful attempt for this matter is as follows:
<ul class="nav nav-pills">
<li ng-class="{ active:tab.isSet(x.name) }" ng-repeat="x in states">
<a href ng-click="tab.setTab(x.name)">{{x.name}} <span class="badge">{{x.elector}}</span></a>
</li>
</ul>
And, inside my controller I have this piece of code for that matter:
$scope.tab = "Alabama";
$scope.isSet = function(checkTab) {
return $scope.tab === checkTab;
};
$scope.setTab = function(activeTab) {
$scope.tab = activeTab;
};
By the way, at first I tried to make the pills active by comparing their indices but that didn't help. It would be even better if you can help me with a way to do this using the indices. I apologize if there is already a posted solution to this but I couldn't find it.
Thanks in advance!
<ul class="nav nav-pills">
<li ng-class="{ 'active':tab.isSet(x.name) }" ng-repeat="x in states">
<a href ng-click="tab.setTab(x.name)">{{x.name}} <span class="badge">{{x.elector}}</span></a>
</li>
</ul>
Note the quotes around active
I found it, I should've deleted the "tab"s in "tab.isset(...)".

Expression in ng-if of AngularJS

Consider the following snippet
ng-if not working
<div class="row">
<div class="col-md-8">
<ul>
<li ng-repeat="bigL in bigLs">
<span ng-if="isObj(bigL)">{{bigL.note}}</span>
<ul ng-if="bigL instanceof Array">
<li ng-repeat="bigLl in bigL">
{{bigLl}}
</li>
</ul>
</li>
</ul>
</div>
</div>
ng-if working
<div class="row">
<div class="col-md-8">
<ul>
<li ng-repeat="bigL in bigLs">
<span ng-if="isObj(bigL)">{{bigL.note}}</span>
<ul ng-if="isArr(bigL)">
<li ng-repeat="bigLl in bigL">
{{bigLl}}
</li>
</ul>
</li>
</ul>
</div>
</div>
Controller
$scope.isArr = function(bigL){
return bigL instanceof Array;
};
I use ng-if to determine whether a nested ul is required to create (by determinate different data type inside the array bigLs), I come to a situation that ng-if cannot evaluate bigL instanceof Array, I then move this snippet inside a function, with the same context, the ng-of works properly, but still cannot understand why it is a need to wrap the expression inside a function instead of running it directly inside the ng-if.
Appreciate for any clarification, thanks!
I'm not exactly sure of the problem, but there are several things that have bad smells in your code:
Don't use 'instanceof Array', ever. It won't work in an angular expression.
Instead, use angular.isArray(). This will only work in javascript by adding a method to your scope.
So, you would want to do something like this:
Controller:
...
$scope.hasChildren = function(bigL1) {
return angular.isArray(bigL1);
}
Template:
...
<ul ng-if="hasChildren(bigL)">
...
As a bonus, it becomes much easier to unit test this code.

In what scope is ng-repeat "as alias" available

I'm using angular 1.4.8. I want to save filtered result from ng-repeat and use it to determine whether to enable a "load more" button at the bottom of the list. I have looked at this question:
AngularJS - how to get an ngRepeat filtered result reference
And many others, they suggest to use "as alias" from ng-repeat, here's what my code looks like:
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in items | limitTo: totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
{{filteredResult.length}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="totalDisplayed <= filteredResult.length">
more
</button>
However, I found filteredResult.length is displayed fine right after ng-repeat, but the button is never shown. If I try to display filteredResult.length in where the button is, it will show null.
So is there a rule for "as alias" scope? I've seen plenty of examples work but mine doesn't, what am I missing here?
EDIT:
The accepted answer uses controllerAs which indeed will resolve the problem. However, charlietfl's comment using ng-init to save filteredResult to parent scope is also very neat and that's the solution I use in my code eventually.
Probably some of classes in your <ul class="media-list tab-pane fade in active"> or <li class="media"> is selector for a directive that would have its own scope. So you store filteredResult in e.g. tab-pane's scope and then try to have access out of it's scope in outside of ul tag.
Try to use Controller as instead of scope:
angular
.module('plunker', [])
.controller('MainCtrl', function() {
vm = this;
// make an array from 1 to 10
var arr = [];
while (arr.length < 10) {
arr.push(arr.length + 1)
};
vm.items = arr;
vm.totalDisplayed = 5;
vm.filteredResult = [];
});
<body ng-controller="MainCtrl as main">
{{main.items}}
<ul class="media-list tab-pane fade in active">
<li class="media">
<div ng-repeat-start="item in main.items | limitTo: main.totalDisplayed as filteredResult">
{{item}}
</div>
<div class="panel panel-default" ng-repeat-end>
</div>
<div>
filteredResult = {{main.filteredResult = filteredResult}}
</div>
</li>
</ul>
<button ng-click="loadMore()" ng-show="main.totalDisplayed <= main.filteredResult.length">
more
</button>
</body>
http://plnkr.co/edit/drA1gQ1qj0U9VCN4IIPP?p=preview

ng-repeat - content to show if array is empty or null

I've a deep nested ng-repeat lists, and only in the last loop I've to display alternate content if list was empty. I'm new to angular, saw some posts online please help me where can I use content if list is empty. The ng-repeat=sessions in day could be empty.
<ul class="day">
<li ng-repeat="sessions in day">
<ul class="table-view">
<li class="table-view-cell" ng-repeat="(heading, session) in sessions">
<span class="group">{{heading}}</span>
<ul class="cell">
<li class="cell-content" ng-repeat="val in session" ng-click="getSession(val.id)">
<div class="time" style="background-color:#{{val.color}}">
<span>{{val.start | date:"h:mma"}}</span>
<span>to</span>
<span>{{val.end | date:"h:mma"}}</span>
</div>
<div class="session" ng-class-odd="'odd'" ng-class-even="'even'">
<span class="name">{{val.name}}</span>
<span class="room">Room: {{val.room}}</span>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
1). CSS approach. I usually use pure CSS approach in such cases. With this markup (stripped extra-html):
<ul class="day">
<li ng-repeat="sessions in day">
...
</li>
<li class="no-sessions">
No sessions on this day.
</li>
</ul>
and CSS rules to hide .no-sessions li by default and make it visible only if there are no previous li tags:
li.no-sessions {
display: block;
}
li + li.no-sessions {
display: none;
}
So when sessions array is empty, there will be no li rendered and only no-sessions one will be visible. And if will hide as soon as there is at least one session on this day.
Demo: http://plnkr.co/edit/KqM9hfgTTiPlkdmEevDv?p=preview
2). ngIf approach. Of course you can use ngIf/ngShow directives for show no-records element when sessions array is empty:
<li ng-if="!day.length">
No sessions on this day.
</li>
I think this would work for your case:
<li ng-hide="day.length > 0">
No sessions on this day.
</li>
No extra CSS needed. Assumes day is an array.
http://plnkr.co/edit/WgDviOKjHKS1Vt5A5qrW
I would recommend handling that in your controller. Keeping your logic in the controller and javasript makes debugging easier and more manageable. I can think of 2 approaches: using ng-show/ng-hide or a condition for your day variable when its empty.
Option 1
ng-show/ng-hide approach:
$scope.isDayEmpty = function(){
return $scope.day.length > 0 ? false : true;
}
html:
<ul class="day">
<li ng-repeat="sessions in day" ng-hide="isDayEmpty">
...
</li>
<li ng-show="isDayEmpty">
No Sessions this Day
</li>
</ul>
Option 2:
ng-repeat approach
if($scope.day.length == 0){
$scope.day.push("No Sessions this Day");
}
This should get you essentially the same result. The first approach would make your CSS styling easier assuming you want to do something different in that case.
The second approach can vary in style depending on your code but thats an example of how you can do it. I don't know your javascript so I can't be more specific to your scenario.

Resources