select JSON object based on ui-router url - javascript

EDIT: Better phrasing of the question. I am basically looking at how to use the variable stored in $scope.item (grabbed from URL using $stateParams) to access the related object in the products JSON array.
Alright so I have used a combination of ui-router and ng-ref so that when you click a product on the "#/shop/" page it creates a URL "#/shop/productname" that when navigated to opens a blank div on the page that is meant to contain details about the product mentioned in the URL.
The issue I am having, and I'm sure there is something simple I am overlooking, is how to get the corresponding data based on the name in the URL? So that I can display product name/price etc that is stored in a JSON object?
Any help would help a ton! It's very possible I am going about this all wrong so please refer me in the right direction if you feel I could choose a better path.
HTML:
shop.html URL: #/shop
...
<a ng-repeat="item in businesses | filter:{cat: cat} | filter:query"
ng-class="{active: item.selected}"
ng-href="#/shop/{{item.link}}"
ng-click="selectedItem(item)">
...
</a>
<div ui-view></div>
...
product.html URL: #/shop/productName
<h1>item.name</h1>
<h2>item.price</h2>
App.js
angular.module('app', [
'ngAnimate',
'ui.router'
])
.config(function ($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/shop');
$stateProvider
.state('shop',{
url: '/shop',
templateUrl: 'templates/shop.html',
controller: 'starWarsCtrl'
})
.state('shop.item',{
url: '/:item',
templateUrl: 'templates/three-quarter-page.html',
controller: function($scope, $stateParams){
$scope.item = $stateParams.item;
}
})
;
})
.controller('appCtrl', function ($scope) {
$scope.products = [
{
"name": "Product 1",
"index":1,
"link":"product1",
"price":"TBD",
}
];
$scope.selectItem = function (selectedItem){
_($scope.products).each(function (item){
item.selected = false;
if (selectedItem === item){
selectedItem.selected = true;
}
})
};
}) /*End Controller*/
});

This will get the selected item for you, assuming you match by the name.
$scope.selectedItem = _.where($scope.products, {name: $scope.item});

I think, if I were you I would use angular service to share data between controllers
and this service will handle the data for me so when I change the product it will return the item object
angular.module('app').factory('productsService', function () {
self = this;
self.products = [{
"name": "Product 1",
"index":1,
"link":"product1",
"price":"TBD",
}];
this.findByLink = function(link){
// loop through your data
// returns what found or null
}
return {
products : this.products
findById : this.findById
}
});
and inject this service in each controller
.controller('appCtrl', function ($scope, productsService) {
$scope.products = productsService.products;
..........
and to anther one
.controller('productCtrl', function ($scope, productsService, $stateParams) {
$scope.item = productsService.findById($stateParams.link);
..........

Related

angularjs ui-router nested states new controller not working

I'm stuck with nested states in the ui-router.
I'm rendering a page with regions, countries and people per country
The index.html has three regions as link, EMEA APAC and AMER
the part of the index page has:
<a ui-sref="territory({territory: 'amer'})">AMER</a> <a ui-sref="territory({territory: 'emea'})">EMEA</a> <a ui-sref="territory({territory: 'apac'})">APAC</a>
<ui-view></ui-view>
when the link is clicked, the countries are returned by a $http.post action and displayed by /views/countries.html as:
<h1>This is countries</h1>
<br>
Teritory: {{region}}
<div ng-repeat='country in countries'>
<a ui-sref=".support({country: '{{country}}'})">{{country}}</a ui-sref>
</div>
This is working so far! so I have a .support link on each country.
The problem is now, when I click the link, the state is accepted...cause it is loading the templateURL, but it seems that the controller specified in that state is not loaded.
the angularjs code:
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'views/home.html',
controller: 'supportCtrl'
})
.state('territory', {
url: '/territory/:territory',
templateUrl: 'views/countries.html',
controller: 'countryController'
})
.state('territory.support',{
url: '/:country',
templateUrl: 'views/supporter.html',
controller: 'supportController'
})
});
the support controller is writing a console.log entry...but nothing happens.
the controllers:
supportApp.controller('countryController',['$scope', 'supportService', '$location', '$stateParams', function($scope, supportService, $location, $stateParams){
$scope.fromTerritory = $stateParams.territory;
$scope.getCountries = function(){
var countries = supportService.getCountries($scope.fromTerritory);
countries.then(function(response){
if(response.data.error){
$scope.error = true;
$scope.message = response.data.message;
}
else{
console.log('response OK');
$scope.region = $scope.fromTerritory;
$scope.countries = response.data;
}
});
}
$scope.getCountries();
}]);
supportApp.controller('supportController',['$scope', 'supportService', '$location', '$stateParams', function($scope, supportService, $location, $stateParams){
console.log('in the supportController');
var test = function(){
console.log('supportController country: '+$stateParams.country);
}
test();
}]);
I'm probably doing something wrong here.
The goal is clicking the country and then displaying names of the people belonging to that specific country.
If it's not clear, I can provide more info where needed. But for now it seems that the controller (supportController) for the nested state (.territory.support) is not running / loaded
thank you!
Ok,
I have my answer for now...
because I did not use the <ui-view></ui-view> on the supporter.html the controller was not 'needed' and did not load.
after adding the the consol.log is showing the log entries.

ng-click : pass data selectedItem between pages angularjs

So, I was able to select Items of my list, but the aim is to pass the data of the selected list in another /route when I click on it. I would need a bit of help because I don't really know how to proceed please. If you know punker examples do not hesitate to tell me :)
Bellow is my optionSuggestionController
app.controller('optionSuggestionController', ['$scope', '$http', function($scope, $http) {
$http.get('suggestions.json')
.then(function(res){
$scope.suggestions = res.data;
});
$scope.setMaster = function(suggestion) {
$scope.selected = suggestion;
}
$scope.isSelected = function(suggestion) {
return $scope.selected === suggestion;
}
}])
Bellow is my list of data
<ul class="list-holder">
<li ng-repeat="suggestion in suggestions" ng-class="{active : isSelected(suggestion)}">
<a ng-click="setMaster(suggestion)">{{suggestion.fromto}}</a>
</li>
</ul>
Bellow is my suggestions.json
[{ "fromto": "Dublin to London", "img": "http://placekitten.com/100/100" },
{ "fromto": "Dublin to Paris", "img": "http://placekitten.com/100/100" },
{ "fromto": "Dublin to Mexico", "img": "http://placekitten.com/100/100" }]
I think you can use the provider '$rootScope'.
$rootScope.selected = suggestion;
You can access this data in an other controller.
Hope it helps.
I have two suggestions:
You can use the provider '$rootScope'.
$rootScope.selected = suggestion;
Or get param via url by provider '$route'.
var suggestion = $route.current.params.suggestion;
You can use Service or Factory to share your data between controllers, I create a Factory with your codes and call it on a control to use.
app.controller('optionSuggestionController', function ($scope, $filter, $timeout, $timeout, $http, testFactory) {
testFactory.get(function (resp) {
console.log(resp);
$scope.suggestions = resp;
});
});
app.factory('testFactory', function ($http) {
var databaseFactory = {};
databaseFactory.get = function (callback) {
return $http.get('suggestions.json').then(function (response) {
databaseFactory.returnedData = response.data;
callback(databaseFactory.returnedData);
});
}
return databaseFactory;
});

AngularJS - Passing ID from a page and populate in other page

I am new to AngularJS. In my project I have a search screen when search I will get the search result in the ngGrid.
On click of any row in the grid, it should populate the details of that row in other page. Basically, I need to pass the ID of the selected record to the other page. I don't know how to handle this in AngularJS (I am using AngularJS HotTowel template) and Breeze for data access logic.
Appreciate if you could provide me link or any where it is implemented which I could refer.
You can create service and share values for instance
var myApp = angular.module('myApp', []);
myApp.factory('ShareData', function() {
var shared;
return {
setValue: function(val){
shared = val;
},
getValue: function(){
return shared;
}
});
function FirstCtrl($scope, ShareData){
ShareData.setValue(1);
}
function SecondCtrl($scope, ShareData){
$scope.data = ShareData.getValue();
}
You need $routeParams for this.
Below is an example of the routing configuration:
var app = angular.module("app", ["ngRoute"])
.config(["$routeProvider", function ($routeProvider) {
$routeProvider
.when("/", {
controller: "HomeController",
templateUrl: "/home/main",
})
.when("/products/:category", {
controller: "ProductController",
templateUrl: "/product/index"
})
.otherwise({
redirectTo: "/"
});
}]);
Product Controller
angular.module("app")
.controller("ProductController",["$scope","$routeParams", function($scope,$routeParams){
$scope.category = $routeParams.category;
alert($scope.category);
}]);
'Main' View
<a ng-href="#/products/ladies">Ladies</a>
check this URL for more info:
https://docs.angularjs.org/api/ngRoute/service/$routeParams

How to get every object in an JSON array in Angular

I'm new in AngularJS, and JS overall. But I think it's fairly simple coming from Java in school.
My first service contained this:
app.factory('User', function($http) {
var user = {
username : null,
company : null,
address : null,
city: null,
country: null
};
$http.get('/webservice/user').success(function(data){
user.username = data.username;
user.company = data.company;
user.address = data.address;
user.city = data.city;
user.country = data.country;
})
return user;
})
I accessed it from the UserCtrl:
app.controller('UserCtrl', ['$scope', 'User', function ($scope, User){
$scope.user = User;
}]);
And in the index.html I simply called:
{{user.username}} {{user.company}} ...
And so forth.
Now I have an array of objects, I use this method:
app.factory('Cards', function($http) {
var cards = [{id:null, name: null, info: null}];
$http.get('/webservice/cards').success(function(data){
for(var i=0;i<data.length;i++){
cards[i] = data[i];
}
})
return cards;
})
The controller looks the same.
app.controller('SearchCtrl', ['$scope', 'Cards', function ($scope, Cards){
$scope.cards = Cards;
}]);
And I access them with a
<li ng-repeat="card in cards">
{{card.id}} {{card.info}}</li>
My question is, do I really have to have a for loop in the $http.get() method?
No Need for the loop, angular js ng-repeat itself works as an foreach loop.
// Js Code
app.factory('Cards', function($http) {
$scope.cards = [];
$http.get('/webservice/cards').success(function(data){
$scope.cards = data;
}
return $scope.cards;
})
//html
<li ng-repeat="card in cards">
{{card.id}} {{card.info}}</li>
I solved this by using ngResource.
When doing using RESTful APIs this is the way to do it. Instead of using the $http.get() method, I simply used
app.factory('CardService', ['$resource', function($resource) {
return $resource('/webservice/cards',{});
}]);
Using $scope inside of a service is not recommended, that way you have lost the functionality of the service.
In the controller, I then used:
app.controller("CardCtrl", ['$scope', 'CardService', function($scope, CardService){
$scope.cards = CardService.query();
})
Using the other ways caused conflict in the 2-way-binding. First it launched the controller, then checked the service, then the controller, then the service again. When working with an object, this worked great. Working with an array, this way is better.

AngularJS - Pass parameters into Controller?

I'm trying to create a simple blog website using AngularJS. I'm just starting out, so what I'm thinking my not be the best way to do this, so any alternative suggestions are welcome.
I have a controller.js file with two blog controllers. One to display a list of blog posts, and the other that displays the post content by including an HTML file.
controller.js
myAppControllers.controller('BlogListCtrl', ['$scope', '$http', function ($scope, $http) {
$http.get('articles/articles.json').success(function (articles) {
$scope.articles = articles;
});
}]);
myAppControllers.controller('BlogPostCtrl', ['$scope', '$routeParams', function ($scope, $routeParams) {
$scope.includeFile = 'articles/' + $routeParams.blogPostId + '.html';
}]);
articles.json
[
{
"id": "test-article-one",
"title": "Test Article one",
"author": "Gareth Lewis",
"datePosted": "2015-06-23",
"summary": "This is a test summary"
},
{
"id": "test-article-two",
"title": "Test article two",
"author": "Gareth Lewis",
"datePosted": "2015-06-23",
"summary": "This is a test for article two"
}
]
app.js
when('/blog', {
templateUrl: 'partials/blog-articles.html',
controller: 'BlogListCtrl'
}).
when('/blog/:blogPostId', {
templateUrl: 'partials/blog-post.html',
controller: 'BlogPostCtrl'
}).
blog-post.html
<ng-include src="'partials/header.html'"></ng-include>
<!-- Want to add title, author, datePosted information here... -->
<article class="content">
<ng-include src="includeFile"></ng-include>
</article>
This blog listings work fine. When I click into a blog post, it also serves up the content from the HTML file OK as well. However, I want to be able to reuse the title, author and datePosted properties from the selected article in the blog-post.html partial view. What's the best way to do this? Would I need to pass them to the Controller somehow to then pass to the view? I don't really want to pass these as routeParams. Or would I need to do a $http.get on articles.json and iterate through to find the selected article and then pass the property values back to the view?
Thanks for the help.
You said that suggestions are welcome, so here it goes.
1 - Transport all your Blog logic to a service;
2 - Provide the data on resolving routes. This is a better approach to handle errors during the load time, 404s, and so on. You can provide a listener to $routeChangeError and deal with it there;
3 - On the service declared below, you have the methods to call your data and a method to retrieve the list cached on the service:
// services.js
myAppServices
.service('BlogService', ['$http', '$q', function ($http, $q) {
var api = {},
currentData = {
list: [],
article: {}
};
api.getSaved = function () {
return currentData;
};
api.listArticles = function () {
var deferred = $q.defer(),
backup = angular.copy(currentData.list);
$http.get('articles/articles.json')
.then(function (response) {
currentData.list = response;
deferred.resolve(response);
}, function () {
currentData.list = backup;
deferred.reject(reason);
});
return deferred.promise;
};
api.getArticle = function (id) {
var deferred = $q.defer(),
backup = angular.copy(currentData.article),
path = 'articles/' + id + '.html';
$http.get(path, {
cache: true
})
.then(function (response) {
currentData.article = {
path: path,
response: response
};
deferred.resolve(currentData.article);
}, function (reason) {
currentData.article = backup;
deferred.reject(currentData.article);
});
return deferred.promise;
};
return api;
}]);
The BlogService.getSaved() will retrieve the stored data, made after each call.
I've made a method to call the ng-include path too, so you can verify if it exists, with cache === true, the browser will keep a copy of it, when calling it again on the view. A copy of the response of the blog article is made too, so you can access its path and the response whenever you need.
On the controllers below, they were adaptated to supply the current needs:
// controller.js
myAppControllers
.controller('BlogListCtrl', ['$scope', 'articles',
function ($scope, articles) {
$scope.articles = articles;
/* OTHER STUFF HERE */
}
])
.controller('BlogPostCtrl', ['$routeParams', '$scope', 'article' 'BlogService',
function ($routeParams, $scope, article, BlogService) {
// On `article` dependency, you have both the original response
// and the path formed. If you want to use any of it.
$scope.includeFile = article.path;
// To get the current stored data (if any):
$scope.articles = BlogService.getSaved().list;
// Traverse the array to get your current article:
$scope.article = $scope.articles.filter(function (item) {
return item.id === $routeParams.id;
});
/* OTHER STUFF HERE */
}
]);
And the route declarations were changed to load the data when resolving the routes.
// app.js
$routeProvider
.when('/blog', {
templateUrl: 'partials/blog-articles.html',
controller: 'BlogListCtrl',
resolve: {
articles: ['BlogService', '$routeParams', function (BlogService, $routeParams) {
return BlogService.listArticles();
}]
}
})
.when('/blog/:id', {
templateUrl: 'partials/blog-post.html',
controller: 'BlogPostCtrl',
resolve: {
article: ['BlogService', '$routeParams', function (BlogService, $routeParams) {
return BlogService.getArticle($routeParams.blogPostId);
}]
}
})
This is maybe a common question in angular. What you have to understand is that Scope is defined per controller... In order to share data across controller you still have the option to use $scope.$parent or $rootScope to link controllers but I would use those carefully.
It is better to use Angular Services which are based on singleton patterns therefore you can use them to share information between controllers and I think it will be a better approach.
I found that this has been previously discussed and here are some good examples:
AngularJS Service Passing Data Between Controllers
You can use a global scope to set this data, or you can use service to communicate between the controllers. There is a lot of ways to resolve this problem read a little bit more about services in the link bellow and see if you can find how to resolve your problem.
AngularJS: Service vs provider vs factory

Categories

Resources