nested ng-repeat with json and rest api call back - javascript

I am trying to make a UI using list of product in a json(products.json) file on local and their availability in number from wp rest api call back in html(ionic) I have this:
Controller:
.controller('ShopCtrl', function($scope, $ionicActionSheet, BackendService, CartService, $http, $sce ) {
$scope.siteCategories = [];
$scope.cart = CartService.loadCart();
$scope.doRefresh = function(){
BackendService.getProducts()
.success(function(newItems) {
$scope.products = newItems;
console.log($scope.products);
})
.finally(function() {
// Stop the ion-refresher from spinning (not needed in this view)
$scope.$broadcast('scroll.refreshComplete');
});
};
$http.get("http://example.com/wp-json/wp/v2/categories/").then(
function(returnedData){
$scope.siteCategories = returnedData.data;
console.log($scope.siteCategories);
}, function(err){
console.log(err);
});
Template view:
<div ng-repeat = "product in products">
<div class="item item-image" style="position:relative;">
<img ng-src="{{product.image}}">
<div ng-repeat = "siteCategory in siteCategories">-->
<button class="button button-positive product-price" ng-click="addProduct(product)">
<p class="white-color product-price-price">post <b>{{siteCategory[$index].count}}</b></p>
</button>
</div>
</div>
<div class="item ui-gradient-deepblue">
<h2 class="title white-color sans-pro-light">{{product.title}} </h2>
</div>
<div class="item item-body">
{{product.description}}
</div>
</div>
so how can I achieve that? I tried to use nested ng-repeat but it didn't work out.

Related

$scope updates not shown in Angularjs

$scope doesn't seems to sync with updates in Angularjs.
I update my time values (myst and myet) using ui.bootstrap.timepicker, then when I display userscheds[index] using alert(JSON.stringify($scope.userscheds[index]));, only the original values are displayed. Something I'm missing?
Any help would be appreciated
See my plunker or code below
update #1
Comment from #dgig to remove this. in ng-model="this.myst". Changed to ng-model="myst"
But my $scope still not shown with the updates done
html modal
<div class="container" ng-app="appUserSchedule">
<div ng-controller="CtrlUserSchedule" >
<div class="row">
<ul>
<li ng-repeat="x in userscheds">{{x.week_day}} {{x.time_start}}-{{x.time_end}}
<span ng-click="ctrl.showModal($index)" style="cursor:pointer;">Edit</span>
<span ng-click="ctrl.removeItem($index)" style="cursor:pointer;">Delete</span>
</li>
</ul>
</div>
<!-- Modal -->
<script type="text/ng-template" id="modalContent.html">
<div class="modal-body">
<div class="row">
<div class="col-sm-6">
<timepicker ng-model="myst" hour-step="1" minute-step="15" show-meridian="true"></timepicker>
</div>
<div class="col-sm-6">
<timepicker ng-model="myet" hour-step="1" minute-step="15" show-meridian="true"></timepicker>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="$close()">OK</button>
<button class="btn btn-primary" ng-click="saveUserScheduleEntry()">Save</button>
</div>
js
var app = angular.module("appUserSchedule", ['ui.bootstrap']);
app.controller("CtrlUserSchedule", function($scope,$http,$location,$modal) {
$scope.ctrl = this;
$http.get('userschedule.json').success(function(data, status, headers, config) {
$scope.userscheds = data.userschedules;
//console.log(data);
}).error(function(data, status, headers, config) {
console.log("No data found..");
});
// Show modal
this.showModal = function (index) {
var modalInstance;
modalInstance = $modal.open({
templateUrl: 'modalContent.html',
controller: 'CtrlUserSchedule',
scope: $scope
});
objts = new Date($scope.userscheds[index].datetime_start);
objte = new Date($scope.userscheds[index].datetime_end);
$scope.myst = objts;
$scope.myet = objte;
// Save User Schedule Entry details after making a change, then close modal
$scope.saveUserScheduleEntry = function() {
// Displays original value, but where are my updated values?
alert(JSON.stringify($scope.userscheds[index]));
$http.put('userschedule.json',index).success(function(eventsuccess){
}).error(function(err){
/* do something with errors */
});
modalInstance.close();
};
}
json
{
"userschedules":[
{
"id":1,
"week_day":"Monday",
"datetime_start":"2016-03-08T08:00:00-05:00",
"datetime_end":"2016-03-08T12:00:00-05:00",
"time_start":"08:00",
"time_end":"12:00"
},
{
"id":21,
"week_day":"Monday",
"datetime_start":"2016-03-08T13:00:00-05:00",
"datetime_end":"2016-03-08T17:00:00-05:00",
"time_start":"13:00",
"time_end":"17:00"
}, ...

Using ngInfiniteScroll to output JSON from a remote source

I have made a small app using AngularJS 1.4, that outputs JSON data from a remote source.
Here is the JSON data in question.
Here is my view - the link to ngInfiniteScroll comes in at the top of the container:
<body ng-app="cn" ng-controller="MainCtrl as main">
<div id="header" class="container-fluid">
<p>Camper News</p>
</div>
<div class="container">
<div infinite-scroll="feed.loadMore()" infinite-scroll-distance="3">
<div ng-repeat="newsItem in myData" class="news-row col-sm-12 col-xs-12">
<div class="col-sm-2 col-xs-12">
<div id="img-container">
<img ng-src={{newsItem.author.picture}} id="user-avatar" />
</div>
</div>
<div class="news-text col-sm-10 col-xs-12">
<a href={{newsItem.link}}><em>{{newsItem.headline}}</em></a>
</div>
<div class="col-sm-10 col-xs-12" id="link-description">
{{newsItem.metaDescription}}
</div>
<div class="col-sm-12 col-xs-12" id="bottom-text">
<div class="col-sm-4 col-xs-12" id="author">
<a href='http://www.freecodecamp.com/{{newsItem.author.username}}'>{{newsItem.author.username}}</a>
</div>
<div class="col-sm-4 col-xs-12" id="likes">
<i class="fa fa-thumbs-o-up"></i> {{newsItem.upVotes.length}}
</div>
<div class="col-sm-4 col-xs-12" id="timestamp">
<span am-time-ago={{newsItem.timePosted}} | amFromUnix></span>
</div>
</div>
</div>
</div>
</div>
</body>
I am attempting to stagger the loading and outputting of the data using ngInfiniteScroll. I'm just not sure how it would work:
app.controller('MainCtrl', function($scope, Feed) {
$scope.feed = new Feed();
});
app.factory('Feed', function($http) {
var Feed = function() {
this.items = [];
this.after = '';
};
Feed.prototype.loadMore = function() {
var url = "http://www.freecodecamp.com/news/hot";
$http.get(url).success(function(data) {
var items = data;
// Insert code to append to the view, as the user scrolls
}.bind(this));
};
return Feed;
});
Here is a link to the program on Codepen. The code that relates to ngInfiniteScroll (controller and factory) is currently commented out in favour of a working version, but this of course loads all links at once.
What do I need to insert in my factory in order to make the JSON load gradually?
From what I can tell, by looking at FreeCodeCamps' story routes, there is no way to query for specific ranges of the "hot news" stories.
It looks to just return json with a fixed 100 story limit.
function hotJSON(req, res, next) {
var query = {
order: 'timePosted DESC',
limit: 1000
};
findStory(query).subscribe(
function(stories) {
var sliceVal = stories.length >= 100 ? 100 : stories.length;
var data = stories.sort(sortByRank).slice(0, sliceVal);
res.json(data);
},
next
);
}
You can use infinite scroll for the stories it does return to display the local data you retrieve from the request in chunks as you scroll.

HTTP.GET isn't working

I'm trying to load a image from a HTTP.GET into my application. I'm unsure why the picture isn't loading.
Here is my code:
Html:
<ion-view view-title="Gallery" align-title="center" ng-controller="photoCtrl">
<ion-content class="center" ng-init="getImages()">
<div class="item item-divider">
<i class="ion-images"></i> Under6/7/8/9s Photos
</div>
<a class="item item-list-detail">
<ion-scroll direction="x">
<img on-hold="onHold()" ng-repeat="image in images" ng-src="images" ng-click="showImages($index)" class="image-list-thumb" />
</ion-scroll>
</a>
</ion-content>
</ion-view>
Javascript:
.controller("photoCtrl", function($scope, $http) {
$scope.data = [];
$scope.getImages = function() {
$http.get('https://api.myjson.com/bins/1jovy')
.success(function(data) {
$scope.data = data;
})
}
});
Add your photoCtrl controller to your view
I saw ng-repeat="data in data", here item and collection is having same name, which is not a good practice....
If I am rewiting this as ng-repeat="img in data" then your ng-src will be like
ng-src="{{img}}"
updated CODEPEN

How do I refresh my ng-repeat?

I have a controller (called "catalogueController") that manages my search box and my search page. I have the controller initially set the page to automatically call the search function defined in "catalogueController" when the app loads to pre-load my array of items (called Inventory) to be repeated via ng-repeat in the page.
The process runs like this:
1. I submit the search form.
2. "catalogueController" will send the search term to my factory (called "Search").
3. "Search" will have a function which will make a server call to query my database for that particular search.
4. The database will send the results of the search to the "Search" factory.
5. The "Search" factory will send the results to the "catalogueController" controller.
6. "catalogueController" will update the $scope.Inventory to be equal to the new result that I was received.
My problem is that ng-repeat does not refresh itself to display my new and updated $scope.Inventory array. $scope.Inventory definitely is updated (I have made sure of this through various console logs).
I have also tried to use $scope.$apply(). It did not work for me.
Thank you in advance for your help!
Here is my code:
HTML Template
<form role="search" class="navbar-form navbar-left" ng-controller="catalogueController" ng-submit="search(search_term)">
<div class="form-group">
<input type="text" placeholder="Search" class="form-control" ng-model="search_term">
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
<main ng-view></main>
catalogue.html partial
<div id="main" class="margin-top-50 clearfix container">
<div ng-repeat="items in inventory" class="row-fluid">
<div class="col-sm-6 col-md-3">
<div class="thumbnail"><img src="image.jpg" alt="..." class="col-md-12">
<div class="caption">
<h3>{{ items.itemName }}</h3>
<p>{{ items.description }}</p>
<p>Buy <a href="#" role="button" class="btn btn-default">More Info</a></p>
</div>
</div>
</div>
</div>
"app.js" Angular App
var myApp = angular.module('qcbApp', ['ngRoute', 'ngCookies', 'appControllers']);
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'html/partials/login.html',
controller: 'registrationController'
}).
when('/sign-up', {
templateUrl: 'html/partials/sign-up.html',
controller: 'registrationController'
}).
when('/catalogue', {
templateUrl: 'html/partials/catalogue.html',
controller: 'catalogueController'
}).
when('/', {
templateUrl: 'html/partials/qcbhome.html'
}).
otherwise({
redirectTo: '/'
});
}]);
"catalogueController" Controller
myApp.controller('catalogueController', ['$scope', 'Search', function($scope, Search) {
var time = 0;
var searchCatalogue = function(search) {
$scope.inventory = null;
console.log("Controller -- "+search);
Search.searchCatalogue(search)
.then(function(results) {
console.log(results);
$scope.inventory = results;
});
};
if(time == 0)
{
searchCatalogue('');
time++;
}
$scope.search = function(term) {
searchCatalogue(term);
}
}]);
"Search" Factory
myApp.factory('Search', ['$http', '$q', function($http, $q) {
function searchCatalogue(term) {
var deferred = $q.defer();
console.log("Factory -- "+term);
$http.post('/catalogue_data', {term: term}, {headers: {'Content-Type': 'application/json'}})
.success(function(result) {
console.log(result[0].SKU);
deferred.resolve(result);
console.log("Factory results -- "+result);
});
return deferred.promise;
}
return {
searchCatalogue: searchCatalogue
}; //return
}]);
I think the problem is the ng-repeat can not access the inventory in scope. You have to create a div which contains both the form and the ng-repeat.
The html should be:
<div ng-controller="catalogueController">
<!-- Move the controller from the form to parent div -->
<form role="search" class="navbar-form navbar-left" ng-submit="search(search_term)">
<div class="form-group">
<input type="text" placeholder="Search" class="form-control" ng-model="search_term">
</div>
<button type="submit" class="btn btn-default">Search</button>
</form>
<div id="main" class="margin-top-50 clearfix container">
<div ng-repeat="items in inventory" class="row-fluid">
<div class="col-sm-6 col-md-3">
<div class="thumbnail"><img src="image.jpg" alt="..." class="col-md-12">
<div class="caption">
<h3>{{ items.itemName }}</h3>
<p>{{ items.description }}</p>
<p>Buy <a href="#" role="button" class="btn btn-default">More Info</a></p>
</div>
</div>
</div>
</div>
</div>
I've seen the situation a few times where when you are updating a property directly on the $scope object there are interesting problems around databinding to that value (such as inventory). However if you databind to an object property of an object then the databinding works as expected. So for example use a property on $scope. I believe this is a copy by value vs copy by reference issue.
Update all your inventory references as follows
$scope.data.inventory = result;
Also don't forget to update your inventory reference in the html template:
<div ng-repeat="items in data.inventory" class="row-fluid">
Update: I made this plunk to figure it out - http://plnkr.co/edit/0ZLagR?p=preview
I think the primary problem is you have the controller specified twice. I removed it from the form and it started working.

AngularJS not filtering products list

I am having an issue with AngularJS filtering my products list. I have done a few console.log queries on my variables and all seem fine. The problem is that the view does not update to show the filtered products.
Filtering works perfectly fine when you enter the search text in the input box but it does not work when clicking on the Category menu items.
I would like to filter the product list by category when the user clicks on the menu item.
Please see my code below and any help or advice is greatly appreciated.
My app.js
myApp.controller('StoreController', function($scope, $filter, storeFactory, cartFactory) {
$scope.cartTotal = 0;
$scope.cartItems = [];
$scope.categories = [];
$scope.counted = 0;
$scope.filteredProducts = {};
//get the products
storeFactory.getProducts(function(results) {
$scope.products = results.products;
$scope.counted = $scope.products.length;
$scope.filteredProducts = results.products;
});
$scope.$watch("search", function(query){
if($scope.filteredProducts.length) {
$scope.filteredProducts = $filter("filter")($scope.products, query);
$scope.counted = $scope.filteredProducts.length;
}
});
$scope.filterProductsByCategory = function(categoryName){
console.log('category filter');
/*$scope.products.forEach(function(o,i){
console.log('filter');
if( o.category_id !== categoryId ){
$scope.filteredProducts.splice(i,1);
console.log('removing');
console.log(o);
}
});*/
$scope.filteredProducts = $filter("filter")($scope.filteredProducts, categoryName);
console.info('the filtered items');
console.log($scope.filteredProducts);
$scope.counted = $scope.filteredProducts.length;
}
$scope.getCategories = function(){
storeFactory.getCategories(function(results){
$scope.categories = results.rows;
});
}
$scope.getCategories();
});
My store.htm
UPDATE :
I removed the extra controller reference and wrapped everything in one div.
<div ng-controller="StoreController">
<!-- the sidebar product menu -->
<div class="block-content collapse in">
<div class="daily" ng-repeat="category in categories | orderBy:'name'">
<div class="accordion-group">
<div ng-click="filterProductsByCategory(category.category_name)" class="accordion-toggle collapsed">{{category.category_name}}</div>
</div>
</div>
</div>
</div>
<!-- Load store items start -->
<div class="label">Showing {{counted}} Product(s)</div>
<div class="row" ng-repeat="product in filteredProducts | orderBy:'product_name'" style="margin-left: 0px; width: 550px;">
<hr></hr>
<div class="span1" style="width: 120px;">
<!-- <a data-toggle="lightbox" href="#carouselLightBox"> -->
<a data-toggle="lightbox" href="#carouselLightBox{{product.product_id}}">
<!--img alt={{ product.product_name }} ng-src="{{product.image}}" src="{{product.image}}" /-->
<img id="tmp" class="" src="images/products/{{product.product_image_filename}}" alt=""></img>
</a>
<div class="lightbox hide fade" id="carouselLightBox{{product.product_id}}" style="display: none;">
<div class='lightbox-content'>
<img src="images/products/{{product.product_image_filename}}" alt="" />
<!--img alt={{ product.product_name }} ng-src="{{product.image}}" src="{{product.image}}" /-->
<button class="btn btn-primary" id="close_lightbox" ng-click="closeBox(product.product_id, $event)">Close</button>
</div>
<style>
#close_lightbox
{
position: absolute;
top: 5px;
right: 5px;
}
</style>
</div>
</div>
<div class="span6" style="width: 330px; margin-bottom: 15px;">
<h5 style="font-size: 14px; font-weight: bold;">{{product.product_name}}</h5>
<p>{{product.product_description }}</p>
<p>Category : {{product.category_name}}</p>
</div>
<div class="span3">
<p class="price">Price : <strong>R{{ product.product_price }}</strong></p>
</div>
</div>
<!-- end of controller -->
</div>
$scope.filteredProducts = {};
//get the products
storeFactory.getProducts(function (results) {
$scope.products = results.products;
$scope.counted = $scope.products.length;
$scope.filteredProducts = results.products;
});
Is results.products an array of objects or an object of objects? Because $filter('filter')($scope.products,query); expects $scope.products to be an array.
$scope.$watch("search", function (query) {
if($scope.filteredProducts.length) {
$scope.filteredProducts = $filter("filter")($scope.products, query);
$scope.counted = $scope.filteredProducts.length;
}
});
Here's what I'm thinking this should look like and you won't need the $watch statement or the filteredProducts array/object, In controller:
$scope.search = '';
$scope.products = [];
$scope.categories = ['category1','category2','category3'];
// assuming that your store function getProducts returns a promise here
storeFactory.getProducts().then(function(results){
$scope.products = results.products; // needs to be an array of product objects
});
$scope.filterProductsByCategory = function(category){
$scope.search = category;
};
Then in your HTML Partial, this is not exactly how your's is, I'm just showing you here in shorter form what is possible:
<button ng-repeat="cat in categories" ng-click="filterProductsByCategory(cat)">{{cat}}</button>
<div class="row" ng-repeat="product in products | filter:search | orderBy:'product_name'">
<!-- Product Information Here -->
</div>
I created a JSFiddle to demonstrate: http://jsfiddle.net/mikeeconroy/QL28C/1/
You can free form search with any term or click a button for a category.
The side bar is using one instance of StoreController, and the main div is using another instance of StoreController. Each instance having its own scope. The should both use the same controller instance: wrap everything inside a div, and use a unique StoreController for this wrapping div.

Categories