I'm trying to use ng-repeat on a div which should contain a star image, each pie in the JSON has a rating property from 1-5, and I want to use this value to loop out x number of stars. I've got this working somewhat but it's flawed in the way that I can't re-sort the array and make the stars follow the correct item in the list since I'm using [$index] to track the iteration.
My solution is rather ugly as well since I'm creating arrays with as many index placeholders as the value of the rating property, and then pushing this into an array to loop out the appropriate number of images. I would like to have a more elegant solution.
How should I go about this problem without using [$index]?
Snippet of the JSON:
{"pies": [
...
{
"name": "Blueberry pie",
"imageUrl": "img/blueberrypie.png",
"id": "1",
"rating": "5", //Ng-repeat depending on this value
"description": "Blueberry pie is amazing."
},
...
]}
My controller:
pieShopApp.controller('shopCtrl', ['$scope', '$http', '$routeParams', function ($scope, $http, $routeParams) {
$scope.pieId = $routeParams.pieId,
$scope.sortingOptions = ['A-Z', 'Rating'],
$scope.sortingValues = ['name', 'rating'],
$scope.ratings = [],
$http.get('jsons/pies.json')
.success(function(data, status) {
$scope.pies = data;
for (i = 0; i < $scope.pies.pies.length; i++) {
switch ($scope.pies.pies[i].rating) {
case "1": $scope.ratings.push(["1"]); break;
case "2": $scope.ratings.push(["1", "2"]); break;
case "3": $scope.ratings.push(["1", "2", "3"]); break;
case "4": $scope.ratings.push(["1", "2", "3", "4"]); break;
case "5": $scope.ratings.push(["1", "2", "3", "4", "5"]); break;
}
}
console.log($scope.ratings);
})
.error(function(status) {
console.log(status);
})
}]);
The list which contains the pie items:
<div id="pie-list-wrapper">
<ul class="nav">
<a href="#/pies/pieid" ng-repeat="pie in pies.pies | filter:query | orderBy:orderProp">
<li class="list-item rounded-corners box-shadow">
<aside>
<img src="{{pie.imageUrl}}" no-repeat alt="Image of the pie">
</aside>
<header>
<h1 ng-bind="pie.name" id="item-name" class="bold-text"></h1>
</header>
<article>
<span ng-bind="pie.description" id="item-desc"></span>
</article>
<footer id="item-rating">
<div ng-repeat="rating in ratings[$index]" class="rating-box"></div> //Contains the stars
</footer>
</li>
</a>
</ul>
</div>
Outcome:
Checkout this
<div ng-app='myApp' ng-controller="Main">
<span ng-repeat="n in range('5')">Start{{$index}} </span>
</div>
$scope.range = function(count){
var ratings = [];
for (var i = 0; i < count; i++) {
ratings.push(i)
}
return ratings;
}
Change your html to following
<div id="pie-list-wrapper">
<ul class="nav">
<a href="#/pies/pieid" ng-repeat="pie in pies.pies | filter:query | orderBy:orderProp">
<li class="list-item rounded-corners box-shadow">
<aside>
<img src="{{pie.imageUrl}}" no-repeat alt="Image of the pie">
</aside>
<header>
<h1 ng-bind="pie.name" id="item-name" class="bold-text"></h1>
</header>
<article>
<span ng-bind="pie.description" id="item-desc"></span>
</article>
<footer id="item-rating">
<div ng-repeat="start in range(pie.rating)" class="rating-box"></div> //Contains the stars
</footer>
</li>
</a>
</ul>
</div>
I solved this in this way:
"items" is your array of objects in the $scope, accesing the property "rating", you can show the star if the value is less or the same comparing to the "rating" property.
In this example I'm using some icon fonts but for the case of an image is the same thing.
<div ng-repeat="item in items">
<div class="item-offers"">
<img ng-src="{{item.image}}">
<div class="item-not-rating">
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 1"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 2"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 3"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 4"></i>
<i class="icon ion-ios-star icon-rating" ng-if="item.rate >= 5"></i>
</div>
</div>
</div>
I've found a better solution that solves this requirement at all:
https://github.com/fraserxu/ionic-rating
It looks like you are iterating on the pies and that's where the $index gets its value from.
Instead of ng-repeat="rating in ratings[$index]"
you should use ng-repeat="rating in range(pie.rating)"
This way, the rating would follow your pie when ordering.
Then you could completely remove the loop in the controller.
Could you provide just a bit more HTML so that we could see where the $index comes from?
Regards,
Camusensei
EDIT:
You are indeed iterating over pies.pies in
ng-repeat="pie in pies.pies | filter:query | orderBy:orderProp"
So what I wrote earlier should work. See below for exhaustive changes.
Controller:
$http.get('jsons/pies.json')
.success(function(data, status) {
$scope.pies = data;
})
.error(function(status) {
console.log(status);
})
HTML:
<div ng-repeat="rating in range(pie.rating)" class="rating-box"></div>
EDIT2: Sorry, I forgot the range function (inspired from Ariya Hidayat):
$scope.range = function(count){
return Array.apply(0, Array(+count));
}
The problem is that ng-repeat only works with arrays or objects, so you can't say iterate x times (while x is a number)
A solution could be to write a function in JavaScript:
$scope.getNumber = function(num) {
return (new Array(num));
}
An then use this html to show the stars without $index:
<div ng-repeat="rating in getNumber(pie.rating)"></div>
In Angular 1.4+ you get the following error when using an empty array:
Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed.
The following works:
$scope.range = function(count) {
return Array.apply(0, Array(+count)).map(function(value,index){
return index;
});
}
<div ng-app='myApp' ng-controller="Main">
<span ng-repeat="n in range(5)">Start{{$index}} </span>
</div>
Related
I just encounter a problem I have written a directive but its not getting update, I dont know why, in console it does change but in directive it does not.
Here is my directive
mainControllers.directive('mallsproduct', function () {
return {
restrict: 'E',
scope: {
productInfo: '=info',
linkid: '=linkid'
},
templateUrl: 'directives/dashboard_product.html'
};
});
Here is my `html`
<div class="aa-properties-content-body mg-7" ng-controller="DashboardController as ctrl">
<ul class="aa-properties-nav aa-list-view">
<li style="border: 1px solid #ccc;margin-bottom: 25px;" ng-repeat="active_products in productInfo.items">
<article class="aa-properties-item mg-top-0-notimp">
<a class="aa-properties-item-img" href="#/product/{{active_products.id}}">
<img ng-if="active_products.photos[0].path" resize-image alt="img" class="" src="{{active_products.photos[0].path}}">
<img ng-if="!active_products.photos[0].path" resize-image class="" src="img/default_product.jpg" alt="">
</a>
<div class="aa-properties-item-content">
<div class="aa-properties-about padding-0-notimp">
<h5>{{active_products.name| limitTo : 10}}{{active_products.name.length > 10 ? '...' : ''}}</h5>
<p class="font-size-11-imp"><i class="fa fa-building-o" aria-hidden="true"></i> {{active_products.mall.name| limitTo : 10}}{{active_products.mall.name.length > 10 ? '...' : ''}}</p>
<p class="font-size-11-imp"><i class="fa fa-map-marker" aria-hidden="true"></i> {{active_products.mall.address| limitTo : 10}}{{active_products.mall.address.length > 10 ? '...' : ''}}</p>
<p class="font-size-11-imp"><i class="fa fa-phone" aria-hidden="true"></i> {{active_products.shop.telephone}}</p>
<p class="font-size-11-imp" ng-if="linkid == 3"><i class="fa fa-eye" aria-hidden="true"></i> {{active_products.views}}</p>
<div class="modal-demo">
<script type="text/ng-template" id="myModalContent.html">
<div ng-include src="'partials/update_product.html'"></div>
</script>
<div ng-controller="AddProductController">
<button ng-click="view_product(active_products.id)"><i class="fa fa-pencil" aria-hidden="true"></i></button>
<button ng-click="del_product(active_products.id)"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
<button ng-if="linkid == 2" ng-init="status = 1" ng-click="reactivate_product(active_products.id, status)"><i class="fa fa-lock" aria-hidden="true"></i></button>
</div>
<div class="modal-parent">
</div>
</div>
</div>
</div>
</article>
</li>
</ul>
<div class="aa-title pad-top-30" ng-if="linkid == 1">
<p>Global page count for active product is {{global_pagecount}} and active product count from API is {{productInfo._meta.pageCount}}</p>
<h3 ng-if="global_pagecount < productInfo._meta.pageCount" class="text-align-center color-feroz cursor-pointer" ng-click="load_more(global_pagecount, linkid)">{{$root.translated_labels.dashboard.load_more}}</h3>
</div>
<div class="aa-title pad-top-30" ng-if="linkid == 3">
<p>Global page count for most viewed is {{global_pagecount_mostv}} and most viewed count from API is {{productInfo._meta.pageCount}}</p>
<h3 ng-if="global_pagecount_mostv < productInfo._meta.pageCount" class="text-align-center color-feroz cursor-pointer" ng-click="load_more(global_pagecount_mostv, linkid)">{{$root.translated_labels.dashboard.load_more}}</h3>
</div>
</div>
I am including directive in dashboard partial like this
<div class="active tab-pane" ng-if="linkid === '1'">
<malls-product info="active_products" linkid="linkid"></malls-product>
</div>
<!--Active products list ends here -->
<!-- Get Inactive Products -->
<div class="active tab-pane" ng-if="linkid === '2'" >
<malls-product info="$root.inactive_products" linkid="linkid"></malls-product>
</div>
<!--Get Inactive products ends here -->
<div class="active tab-pane" ng-if="linkid === '3'" >
<malls-product info="$root.mostviewed_products" linkid="linkid"></malls-product>
</div>
<!-- View Profile-->
and This is the api which does show the result in console.
$scope.global_pagecount = 1;
$scope.active_product = function () {
$http.get($rootScope.baseurl + 'abc?&page=' + $scope.global_pagecount,
{headers:
{'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': $rootScope.keyword_auth_token, 'Accept-Language': $cookies.get('type')}
})
.success(function (data) {
//$scope.active_product_pageCount = data._meta.pageCount;
if ($scope.global_pagecount === 1) //I know for sure the first page of pagination is 1
{
$scope.active_products = data;
}
if ($scope.global_pagecount > 1) // If user click load more global count gets incremented and new results push in active_producst
{
/* for loading new results Pagination Applied */
for (var times = data.items.length - 1; times >= 0; times--) {
$scope.active_products.items.push(data.items[times]);
}
}
console.log($scope.active_products);
})
.error(function (data) {
// console.log(data);
});
};
What is the issue, why it is not getting update, If I use rootscopethen it works fine, obviously it has too, but not with $scope.
Note : when scope.global_pagecount value is equal to 2 i get new results but not in directive only in console. By default scope.global_pagecount has value equal to 1.
You don't use your directive correctly. You define it as:
mainControllers.directive('mallsproduct'
Which means you should use it as:
<mallsproduct ..>
Or define your directive camelcased:
mainControllers.directive('mallsProduct'
Then you can use it as you do now:
<malls-product ..>
This is because of the Isolated scope doesn’t know anything about its parent scope. You just created a directive with an isolated scope.
To access any parent scope data, we need to pass the scope data to our directive explicitly. This is achieved by setting properties on the scope object in the DDO.
Another important thing is that, these properties also MUST be set as the attributes of the directive html element.
I am creating app in ionic /angularjs.
The controller fetches the data in JSON format from the URL and displays unique images in div elements. I want to allow these images to be clicked and then display the data according to offer_name, which is coming from the JSON data.
e.g.: Suppose I display the image for Amazon (in background offer_name is amazon (having 10 records)). When the user clicks on that, it displays all the records related to amazon.
Hope you get my point but no database is included; it only works with JSON data.
Also, how can the check current value be checked in ng-repeat?
Here is my code:
.controller('menuCtrl', function($scope,$http) {
$http.get("http://tools.vcommission.com/api/coupons.php?apikey=e159f64e3dd49fddc3bb21dcda70f10c6670ea91aac30c7cb1d4ed37b20c45b8").then(function (response) {
$scope.myData = response.data;
/* $scope.stack=[];
angular.forEach($scope.myData, function(item){
$scope.stack =item.store_image;
var uni_img=[];
for(var i=0 ; i< $scope.stack.length;i++)
{
if(uni_img.indexOf($scope.stack[i] == -1))
uni_img.push($scope.stack[i]);
}
console.log(uni_img);
})*/
});
$scope.dealopen = function($a){
for (var i=0;i<$scope.myData.length;i++)
{
//console.log($scope.data[i].name);
$link=$scope.data[i].offer_name;
if ($link==$a)
{
$window.open($link,"_self","location=yes");
console.log($a);
}
}
}
})
Html
<div class="item col-sm-2 col-sm-3 col-md-2 " ng-repeat="da in myData | unique: 'store_image'" >
<div class="thumbnail">
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}"
/>
<div class="caption">
<b class="group inner list-group-item-heading center-block">
{{da.offer_name | limitTo: 12 }} Deals</b>
<a class="item item-text-wrap" ng-href="#/Deals/{{da.offer_name}}">View Deal</a>
</div>
</div>
</div>
Here is the output:
.
One way to achieve this is to use ng-click to execute javascript (e.g. inline or call a function in the controller scope. Per the documentation for ngRepeat $index can be referenced for the current index:
Special properties are exposed on the local scope of each template instance, including:
+----------+---------+-----------------------------------------------------------------------------+
| Variable | Type | Details |
+----------+---------+-----------------------------------------------------------------------------+
| $index | number | iterator offset of the repeated element (0..length-1) |
| $first | boolean | true if the repeated element is first in the iterator. |
| $middle | boolean | true if the repeated element is between the first and last in the iterator. |
| $last | boolean | true if the repeated element is last in the iterator. |
| $even | boolean | true if the iterator position $index is even (otherwise false). |
| $odd | boolean | true if the iterator position $index is odd (otherwise false). |
+----------+---------+-----------------------------------------------------------------------------+
1
So the image tag can have the attribute ng-click to utilize that directive, like this:
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}" ng-click="showData(da.offer_name, $index)"/>
Then use Array.filter() to filter all offers into a filtered array of offers matching the offer_name:
$scope.showData = function (offer_name, index) {
$scope.offerName = da.offer_name;
$scope.filteredOffers = $scope.myData.filter(function(offer) {
return offer.offer_name == $scope.offerName;
});
}
And then add another set of elements to display the items in filteredOffers.
<div ng-repeat="offer in filteredOffers">
<div class="couponCode">{{offer.coupon_code}}</div>
<div class="couponTitle">{{offer.coupon_title}}</div>
<div class="couponDescription">{{offer.coupon_Description}}</div>
</div>
See the example below where the showData function updates the model selectedIndex, offerName and filteredOffers using these components.
angular.module('myApp', ['ui'])
.controller('menuCtrl', ['$scope', '$http',
function($scope, $http) {
$scope.offerName = ''; //set initially
$scope.selectedIndex = -1;
$scope.filteredOffers = [];
$http.get("http://tools.vcommission.com/api/coupons.php?apikey=e159f64e3dd49fddc3bb21dcda70f10c6670ea91aac30c7cb1d4ed37b20c45b8").then(function(response) {
$scope.myData = response.data;
});
$scope.showData = function(offer_name, index) {
$scope.offerName = offer_name;
$scope.filteredOffers = $scope.myData.filter(function(offer) {
return offer.offer_name == $scope.offerName;
});
$scope.selectedIndex = index;
}
}
]);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js" data-semver="1.1.5" data-require="angular.js#*" context="anonymous"></script>
<script data-require="angular-ui#*" data-semver="0.4.0" src="//rawgithub.com/angular-ui/angular-ui/master/build/angular-ui.js" context="anonymous"></script>
<div ng-app="myApp" ng-controller="menuCtrl">
<div>
OfferName:
<span ng-bind="offerName"></span>
</div>
<div>
selected index:
<span ng-bind="selectedIndex"></span>
</div>
<div class="item col-sm-2 col-sm-3 col-md-2 " ng-repeat="da in myData | unique: 'store_image'">
<div class="thumbnail">
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}" ng-click="showData(da.offer_name, $index)" />
<div class="caption">
<b class="group inner list-group-item-heading center-block">
{{da.offer_name | limitTo: 12 }} Deals</b>
<a class="item item-text-wrap" ng-href="#/Deals/{{da.offer_name}}">View Deal</a>
</div>
</div>
</div>
<div ng-repeat="offer in filteredOffers">
<div class="couponCode">{{offer.coupon_code}}</div>
<div class="couponTitle">{{offer.coupon_title}}</div>
<div class="couponDescription">{{offer.coupon_Description}}</div>
</div>
</div>
1 https://docs.angularjs.org/api/ng/directive/ngRepeat
You can use $index, that is the variable used in agular to know the index position in ng-repeat, if you want to know more about another contro variables of ng-repeat read the docs in the next link https://docs.angularjs.org/api/ng/directive/ngRepeat
An basic example is.
CONTROLLER
app.controller('menuCtrl', function($scope,$http) {
$scope.myData = [{path:'http://www.imagefree1.com',info:'http://www.infoimage1.com'},
{path:'http://www.imagefree2.com',info:'http://www.infoimage2.com'},
{path:'http://www.imagefree3.com',info:'http://www.infoimage3.com'}];
$scope.callDetail=function(index)
window.open(myData[index].info);
})
HTML
<div ng-repeat="image in myData">
<a href="#" ng-click="callDetail($index)">
<img src="image.path" alt="Description"/>
</a>
</div>
At first look you never call the $scope.dealopen function,
may be this can work....
<div class="item col-sm-2 col-sm-3 col-md-2 " ng-repeat="da in myData | unique: 'store_image'" >
<div class="thumbnail">
<img class="thumbnail img-responsive " ng-src="{{ da.store_image}}"/>
<div class="caption">
<b class="group inner list-group-item-heading center-block">{{da.offer_name | limitTo: 12 }} Deals</b>
<a class="item item-text-wrap" ng-click="dealopen(da.offer_name)">View Deal</a>
</div>
</div>
</div>
Hope somebody can help me with my problem.
I am trying to order my list on specific data and this works fine when I say upfront on what it needs to be sorted.
But when I do this when I click on a button it doesn't order my list in anyway.
Hope somebody can help me with this problem.
this is my app.js code:
app.controller("ListController", function ($scope, $interval, $http, myService, OpenDataService) {
myService.async().then(function (d) {
OpenDataService.opendata = d;
$scope.openData = OpenDataService.opendata;
$scope.order = "";
});
$scope.orderOptions = ["gemeente", "locatie"];
$scope.change = function (value) {
console.log("change");
$scope.order = value;
console.log(value);
}
$scope.test = OpenWifiData;
});
And here is the html code I use:
<li ng-click="change('gemeente')"><a>locatie</a></li>
<div id="WifiSpots" ng-controller="ListController" class="col-sm-12 col-md-4 col-md-offset-2">
<div ng-repeat="item in openData | filter:searchText | orderBy: order">
<ul class="list-group">
<li class="list-group-item">
<div class="row wifiSpots" >
<div class="col-md-2">{{item.locatie}}</div>
<div class="col-md-2">{{item.gemeente}}</div>
<div clas="col-md-1">{{item.distance}}</div>
<div clas="col-md-1">{{item.duration}}</div>
<button ng-controller="MapController" ng-click="calculateAndDisplayRoute(item.objectid)" class="btn ">Selecteer</button>
</div>
</li>
</ul>
</div>
</div>
The 'order' in the ng-repeat directive is in a different scope than the one in your controller. Add a wrapper class like so:
$scope.opts = {order: ""};
Then in your change function update that instead:
$scope.opts.order = value;
In the html:
orderBy:opts.order
I want to show data using ng-click
First i have listing for of all the companies, this works fine. it displays all the companies.:
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({id:item.iCompanyID})" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
</div>
Now on click of company name, i have to display other info like packges of that company, for that i have done this under above div:
<div ng-repeat="item in pData" class="col-xs-3">
<a ng-click="" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vPackageName}}</span>
</a>
</div>
In controller.js i did this, getPackageInDetail will return package listing according to company id:
function getPackageInfo(id) {
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
$scope.pData = data;
}).
error(function(data,status,header,config) {
$scope.pData = 0;
});
};
How can i append the data according to company clicked?
Array.prototype.push.apply() can be used for merging two arrays.
Merge the second array into the first one
//Define an empty array
$scope.pData = [];
$scope.getPackageInfo = function(id) {
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
Array.prototype.push.apply($scope.pData, data); //Merge the array
});
};
Additionally, I think you need to pass ID properly
<a ng-click="getPackageInfo(item.iCompanyID)">
I created a list that is searchable with an input using angular.js (ng-model="searchText"). On click of the list elements you can pull the content of the selected item using {{selected | json}}. I want to apply this selected element as the value of the input when a list item is clicked.
I essentially want to create my own autocomplete that always displays a list of options, filters options while typing, and fills in the input on click of an option.
HTML
<html ng-app>
<section>
<div id="content-body" class="container search-page"><!-- begin content-body -->
<div id="content-frame" class="container"></div><!-- end content-frame -->
<section>
<div class="search-container">
<div class="search-wrapper">
<input type="search" class="input-from" autocomplete="off" placeholder="Search" ng-model="searchText" value="{{searchText}}">
</div>
</div>
</section>
<section>
<div ng-controller="ContentCtrl">
<ul class="list-group search">
<!--<li class="list-group-item group-title">
<span class="icon itinerary-icon"></span>
Popular Destinations
</li>-->
<a ng-click="setMaster(cities)" ng-repeat="city in cities | filter:searchText | limitTo:limit" href="#" class="list-group-item">{{city}}</a>
</ul>
</div>
</section>
</div><!-- end content-body -->
</html>
JS
function ContentCtrl($scope, $http) {
"use strict";
$scope.url = '../mobile-site/cities.json';
$scope.cities = [];
$scope.limit = 10; // max 10 cities loaded
$scope.fetchContent = function() {
$http.get($scope.url).then(function(response){
$scope.cities = response.data.cities;
});
}
$scope.fetchContent(); // build cities list
$scope.setMaster = function(city) {
$scope.searchText = city; // pull selected city using {{selected | json}}
}
}
JSON
{
"version": "082B6AF45261B81358E8F99F0FAEC4A4",
"cities": [
"A Friela Maside, Spain",
"A Gudina, Spain",
"AHA, Germany",
"AL, Norway"
]
}
I think you have a few mistakes in the code:
<div ng-model="chosen">
<a ng-click="setMaster(cities)" ng-repeat="cities in cities | filter:searchText | limitTo:limit" href="#" class="list-group-item">{{cities}}</a>
</div>
shoud be
<div ng-repeat="city in cities | filter:searchText | limitTo:limit">
<a ng-click="setMaster(city)" class="list-group-item">{{city}}</a>
</div>
then I think what you want is
$scope.setMaster = function(city) {
$scope.searchText = city;
}
Also, I'm not sure what the ng-model on the div is for, as far as I know it is used only for inputs, textareas and selects. See http://docs.angularjs.org/api/ng.directive:ngModel.
You probably want something like this fiddle -> http://jsfiddle.net/weSpW/3/.