How to get data from json to view in AngularJS - angularjs

I have an Angular controller that gets data via a service from 2 different json files, and I need to pass that data to a view.
The controller file:
.controller('MainController', ['info', function (info){
var vm = this;
info.getAddresses().then(function(data) {
vm.addresses = data.addresses;
});
info.getNames().then(function(data) {
vm.names = data.names;
});
console.log(this);
}])
The getAddresses and getNames functions are just $.get('json-url').
If I use console.log(this) in the controller just before the closing bracket, I can see in the console the data below:
but I cannot access that 2 properties from the view. Am I missing something?

It's probably a digest cycle issue. Adding $scope.$apply would fix the issue.
$.get() from jQuery alter the value of vm.names but it's not part of the Angular digest cycle.
Here is a working example, hope this helps
angular.module('myApp', [])
.factory('info', function() {
var mock = function() {
return new Promise(function(resolve, reject) {
resolve({
"names": ['Alice', 'Bob']
});
});
};
return {
getNames: mock
};
})
.controller('MainController', function(info,$scope) {
var vm = this;
info.getNames().then(function(data) {
vm.names = data.names;
// trigger $apply manually
$scope.$apply();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MainController as vm">
{{vm.names}}
</div>
</div>

use scope variable to store the data instead of var
.controller('MainController', ['info', '$scope', $scope, function (info){
$scope.vm = this;
info.getAddresses().then(function(data) {
$scope.vm.addresses = data.addresses;
});
info.getNames().then(function(data) {
$scope.vm.names = data.names;
});
console.log(this);
}])
and call this scope variable in your view like
<tr ng-repeat = item in vm>
<td>you can get your data here</td>
</tr>
Hope this works

You are assigning your data to a variable and not to the $scope.
Your controller should be like this
.controller('MainController', ['info', '$scope', function (info, $scope){
info.getAddresses().then(function(data) {
$scope.addresses = data.addresses;
});
info.getNames().then(function(data) {
$scope.names = data.names;
});
console.log($scope);
}])

Here you have used controller as syntax. So you need to use it into ng-controller. Check below code.
<div ng-controller="MainController as vm">
<div ng-repeat="vm.addresses in address">{{ address }}</div>
<div ng-repeat="vm.names in name">{{ name}}</div>
</div>
If address or name is json object then you need to use specific key within address or name object.

For Angular 2+
Hold the json response in some variable:
public data:any=your json response;
And then in view, display it vi using *ngFor directive:
<p *ngFor="let d of data">{{d}}</p>

Related

How to invoke function of another controller from different controller

I am using angular js as my client side.
I want to invoke one function which is in another controller.
How can i achieve this?
var app = angular.module('MyApplication', []);
app.controller('Controller1', function($scope, $rootScope) {
$scope.function1 = function() {
console.log('Controller 1 clicked and Function 1 called');
}
//receive the fuction using $on MyFunction
$rootScope.$on("CallController1", function() {
console.log('Controller 2 clicked and Controller 1 called');
});
});
app.controller('Controller2', function($scope) {
$scope.function2 = function() {
console.log('Controller 2 clicked and Function 2 called');
$scope.$emit("CallController1"); //emit the fuction using MyFunction
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="MyApplication">
<div ng-controller="Controller1">
<button ng-click="function1()">function 1</button>
</div>
<br>
<div ng-controller="Controller2">
<button ng-click="function2()">function 2</button>
</div>
</div>
Though it can be done by making use of the rootScope but polluting the rootScope is a risky affair taking into consideration the digest and watch cycles that run whenever the state of the application changes at run time.Burdening it more is not recommended.
The best and cleanest way to share common code or functionality is to use service/factory and then use it in your respective controller.
For e.g. we can create a shared service like below
angular.factory('sharedList', function() {
var list = [];
return {
addItem: addItem,
getList: getList
};
function addItem(item) {
list.push(item);
}
function getList() {
return list;
}
});
and include this service in your controllers as
app.controller("MyCtrl", function($scope, sharedList) {
$scope.users = sharedList.getList();
});
app.controller("AnotherCtrl", function($scope, sharedList) {
$scope.firstUser = sharedList.getList()[0];
});
and in case if you want to add something then you can make the code changes likewise.
Hope it helps.

How to share controller data between two HTML page in Angular JS [duplicate]

I have a basic controller that displays my products,
App.controller('ProductCtrl',function($scope,$productFactory){
$productFactory.get().success(function(data){
$scope.products = data;
});
});
In my view I'm displaying this products in a list
<ul>
<li ng-repeat="product as products">
{{product.name}}
</li>
</ul
What I'm trying to do is when someone click on the product name, i have another view named cart where this product is added.
<ul class="cart">
<li>
//click one added here
</li>
<li>
//click two added here
</li>
</ul>
So my doubt here is, how do pass this clicked products from first controller to second? i assumed that cart should be a controller too.
I handle click event using directive. Also i feel i should be using service to achieve above functionality just can't figure how? because cart will be predefined number of products added could be 5/10 depending on which page user is. So i would like to keep this generic.
Update:
I created a service to broadcast and in the second controller i receive it. Now the query is how do i update dom? Since my list to drop product is pretty hardcoded.
From the description, seems as though you should be using a service. Check out http://egghead.io/lessons/angularjs-sharing-data-between-controllers and AngularJS Service Passing Data Between Controllers to see some examples.
You could define your product service (as a factory) as such:
app.factory('productService', function() {
var productList = [];
var addProduct = function(newObj) {
productList.push(newObj);
};
var getProducts = function(){
return productList;
};
return {
addProduct: addProduct,
getProducts: getProducts
};
});
Dependency inject the service into both controllers.
In your ProductController, define some action that adds the selected object to the array:
app.controller('ProductController', function($scope, productService) {
$scope.callToAddToProductList = function(currObj){
productService.addProduct(currObj);
};
});
In your CartController, get the products from the service:
app.controller('CartController', function($scope, productService) {
$scope.products = productService.getProducts();
});
how do pass this clicked products from first controller to second?
On click you can call method that invokes broadcast:
$rootScope.$broadcast('SOME_TAG', 'your value');
and the second controller will listen on this tag like:
$scope.$on('SOME_TAG', function(response) {
// ....
})
Since we can't inject $scope into services, there is nothing like a singleton $scope.
But we can inject $rootScope. So if you store value into the Service, you can run $rootScope.$broadcast('SOME_TAG', 'your value'); in the Service body. (See #Charx description about services)
app.service('productService', function($rootScope) {/*....*/}
Please check good article about $broadcast, $emit
Solution without creating Service, using $rootScope:
To share properties across app Controllers you can use Angular $rootScope. This is another option to share data, putting it so that people know about it.
The preferred way to share some functionality across Controllers is Services, to read or change a global property you can use $rootscope.
var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
function($scope, $rootScope) {
$rootScope.showBanner = true;
}]);
app.controller('Ctrl2', ['$scope','$rootScope',
function($scope, $rootScope) {
$rootScope.showBanner = false;
}]);
Using $rootScope in a template (Access properties with $root):
<div ng-controller="Ctrl1">
<div class="banner" ng-show="$root.showBanner"> </div>
</div>
You can do this by two methods.
By using $rootscope, but I don't reccommend this. The $rootScope is the top-most scope. An app can have only one $rootScope which will be
shared among all the components of an app. Hence it acts like a
global variable.
Using services. You can do this by sharing a service between two controllers. Code for service may look like this:
app.service('shareDataService', function() {
var myList = [];
var addList = function(newObj) {
myList.push(newObj);
}
var getList = function(){
return myList;
}
return {
addList: addList,
getList: getList
};
});
You can see my fiddle here.
An even simpler way to share the data between controllers is using nested data structures. Instead of, for example
$scope.customer = {};
we can use
$scope.data = { customer: {} };
The data property will be inherited from parent scope so we can overwrite its fields, keeping the access from other controllers.
angular.module('testAppControllers', [])
.controller('ctrlOne', function ($scope) {
$scope.$broadcast('test');
})
.controller('ctrlTwo', function ($scope) {
$scope.$on('test', function() {
});
});
I saw the answers here, and it is answering the question of sharing data between controllers, but what should I do if I want one controller to notify the other about the fact that the data has been changed (without using broadcast)? EASY! Just using the famous visitor pattern:
myApp.service('myService', function() {
var visitors = [];
var registerVisitor = function (visitor) {
visitors.push(visitor);
}
var notifyAll = function() {
for (var index = 0; index < visitors.length; ++index)
visitors[index].visit();
}
var myData = ["some", "list", "of", "data"];
var setData = function (newData) {
myData = newData;
notifyAll();
}
var getData = function () {
return myData;
}
return {
registerVisitor: registerVisitor,
setData: setData,
getData: getData
};
}
myApp.controller('firstController', ['$scope', 'myService',
function firstController($scope, myService) {
var setData = function (data) {
myService.setData(data);
}
}
]);
myApp.controller('secondController', ['$scope', 'myService',
function secondController($scope, myService) {
myService.registerVisitor(this);
this.visit = function () {
$scope.data = myService.getData();
}
$scope.data = myService.getData();
}
]);
In this simple manner, one controller can update another controller that some data has been updated.
we can store data in session and can use it anywhere in out program.
$window.sessionStorage.setItem("Mydata",data);
Other place
$scope.data = $window.sessionStorage.getItem("Mydata");
1
using $localStorage
app.controller('ProductController', function($scope, $localStorage) {
$scope.setSelectedProduct = function(selectedObj){
$localStorage.selectedObj= selectedObj;
};
});
app.controller('CartController', function($scope,$localStorage) {
$scope.selectedProducts = $localStorage.selectedObj;
$localStorage.$reset();//to remove
});
2
On click you can call method that invokes broadcast:
$rootScope.$broadcast('SOME_TAG', 'your value');
and the second controller will listen on this tag like:
$scope.$on('SOME_TAG', function(response) {
// ....
})
3
using $rootScope:
4
window.sessionStorage.setItem("Mydata",data);
$scope.data = $window.sessionStorage.getItem("Mydata");
5
One way using angular service:
var app = angular.module("home", []);
app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});
app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});
app.factory('ser1', function(){
return {o: ''};
});
I've created a factory that controls shared scope between route path's pattern, so you can maintain the shared data just when users are navigating in the same route parent path.
.controller('CadastroController', ['$scope', 'RouteSharedScope',
function($scope, routeSharedScope) {
var customerScope = routeSharedScope.scopeFor('/Customer');
//var indexScope = routeSharedScope.scopeFor('/');
}
])
So, if the user goes to another route path, for example '/Support', the shared data for path '/Customer' will be automatically destroyed. But, if instead of this the user goes to 'child' paths, like '/Customer/1' or '/Customer/list' the the scope won't be destroyed.
You can see an sample here: http://plnkr.co/edit/OL8of9
I don't know if it will help anyone, but based on Charx (thanks!) answer I have created simple cache service. Feel free to use, remix and share:
angular.service('cache', function() {
var _cache, _store, _get, _set, _clear;
_cache = {};
_store = function(data) {
angular.merge(_cache, data);
};
_set = function(data) {
_cache = angular.extend({}, data);
};
_get = function(key) {
if(key == null) {
return _cache;
} else {
return _cache[key];
}
};
_clear = function() {
_cache = {};
};
return {
get: _get,
set: _set,
store: _store,
clear: _clear
};
});
Make a factory in your module and add a reference of the factory in controller and use its variables in the controller and now get the value of data in another controller by adding reference where ever you want
One way using angular service:
var app = angular.module("home", []);
app.controller('one', function($scope, ser1){
$scope.inputText = ser1;
});
app.controller('two',function($scope, ser1){
$scope.inputTextTwo = ser1;
});
app.factory('ser1', function(){
return {o: ''};
});
<div ng-app='home'>
<div ng-controller='one'>
Type in text:
<input type='text' ng-model="inputText.o"/>
</div>
<br />
<div ng-controller='two'>
Type in text:
<input type='text' ng-model="inputTextTwo.o"/>
</div>
</div>
https://jsfiddle.net/1w64222q/
FYI
The $scope Object has the $emit, $broadcast, $on
AND
The $rootScope Object has the identical $emit, $broadcast, $on
read more about publish/subscribe design pattern in angular here
To improve the solution proposed by #Maxim using $broadcast, send data don't change
$rootScope.$broadcast('SOME_TAG', 'my variable');
but to listening data
$scope.$on('SOME_TAG', function(event, args) {
console.log("My variable is", args);// args is value of your variable
})
There are three ways to do it,
a) using a service
b) Exploiting depending parent/child relation between controller scopes.
c) In Angular 2.0 "As" keyword will be pass the data from one controller to another.
For more information with example, Please check the below link:
http://www.tutorial-points.com/2016/03/angular-js.html
var custApp = angular.module("custApp", [])
.controller('FirstController', FirstController)
.controller('SecondController',SecondController)
.service('sharedData', SharedData);
FirstController.$inject = ['sharedData'];
function FirstController(sharedData) {
this.data = sharedData.data;
}
SecondController.$inject['sharedData'];
function SecondController(sharedData) {
this.data = sharedData.data;
}
function SharedData() {
this.data = {
value: 'default Value'
}
}
First Controller
<div ng-controller="FirstController as vm">
<input type=text ng-model="vm.data.value" />
</div>
Second Controller
<div ng-controller="SecondController as vm">
Second Controller<br>
{{vm.data.value}}
</div>
I think the best way is to use $localStorage. (Works all the time)
app.controller('ProductController', function($scope, $localStorage) {
$scope.setSelectedProduct = function(selectedObj){
$localStorage.selectedObj= selectedObj;
};
});
Your cardController will be
app.controller('CartController', function($scope,$localStorage) {
$scope.selectedProducts = $localStorage.selectedObj;
$localStorage.$reset();//to remove
});
You can also add
if($localStorage.selectedObj){
$scope.selectedProducts = $localStorage.selectedObj;
}else{
//redirect to select product using $location.url('/select-product')
}

Need help to understand async calls in angular js

I have a main controller and nested controllers within it. In the main controller I have defined object by async query to the service, and try to use the object in the nested controller. But in the object in the nested controller is empty, cause it fires before it will be updated in the main controller.
As I understand, asyncronous query should updates the scope after data obtain?
.controller('MainController', ['$scope', function($scope) {
$scope.uData = {};
$scope.uDataCurrent = {};
$scope.usersData = usersFactory.getUsersData().query(
function(response) {
$scope.uData = response;
$scope.uDataCurrent = $filter('filter')($scope.uData, {'user':$scope.myuser});
$scope.uDataCurrent = $scope.uDataCurrent[0];
},
function(response) {
$scope.message = "Error: "+response.status + " " + response.statusText;
});
})]
.controller('NestedController', ['$scope', function($scope) {
console.log($scope.uDataCurrent); // returns empty object
}])
Service:
.service('usersFactory', ['$resource', 'baseURL', function($resource,baseURL) {
this.getUsersData = function(){
return $resource(baseURL+"/index.php?app=users&format=raw&resource=user",null, {'update':{method:'PUT' }});
};
}])
You could use $scope.$watch.
angular.module("App", [])
.controller("OuterCtrl", ["$scope", "$timeout", function($scope, $timeout) {
$scope.users = null;
$timeout(function() {
$scope.users = ["John", "Jack"];
}, 500);
}]).controller("InnerCtrl", ["$scope", function($scope) {
$scope.changeCount = 0;
// TODO: Bad practice to rely on outer scopes here as its not enforced
// to have an OuterCtrl scope as parent scope. In this example every
// occurrences of InnerCtrl is embedded in an OuterCtrl in the html
$scope.$watch("users", function(newValue, oldValue) {
// This code runs when the users array is changed
$scope.changeCount++;
});
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.js"></script>
<div ng-app="App">
<div ng-controller="OuterCtrl">
<div ng-controller="InnerCtrl">
<div>Change count: {{changeCount}}</div>
<div>Users</div>
<div ng-hide="users"> Loading...</div>
<ul>
<li ng-repeat="name in users">{{name}}</li>
</ul>
</div>
</div>
</div>

angularjs: not able to pass a variable value from controller to view

(function() {
angular
.module('myApp.home', [])
.factory('myService', function($http) {
return {
getInfo: function() {
// return something
}
};
})
.controller('HomeController', function($scope, $routeParams, myService) {
var my = this;
var sid;
myService.getInfo().success(function(data) {
my.id = data.id;
//sid= my.id;
});
//my.id = sid;
});
})();
I'm trying to access the variable id in my view. But I'm not able to do so. I'm getting an undefined variable error.
I even tried to declare a variable sid globally so that it can be accessed from everywhere and I tried assigning value to it as well but that effort also didn't bring up any results.
My services are working fine and they are returning data. I'm trying to use the id in my view but don't know where I messed it up.
Any help?
EDIT
And my HTML is like this:
<div data-id="my.id"></div>
If you want to use it in your view you have to bind it to a scope e.g. $scope.id - check this link for reference.
Below is your html, how it should be.
<div ng-app="app" ng-controller="HomeController as home">
<div data-id="home.id">{{home.id}}</div>
</div>
Below is how your controller part.
angular.module('app', [])
.controller('HomeController', function () {
this.id = "someValue";
});
http://jsfiddle.net/grdmLfxt/
use controllerAs : vm then you can access vm.id in your view.
HTML
<div ng-app="app" ng-controller="HomeController as vm">
<div data-id="vm.id">{{vm.id}}</div>
</div>
Controller
.controller('HomeController', function () {
var vm = this;
vm.id = "someValue";
});
for more info read this
small change in javascript code and html. try this.
Javascript
(function() {
angular
.module('myApp.home', [])
.factory('myService', function($http) {
return {
getInfo: function() {
// return something
}
};
})
.controller('HomeController', function($scope, $routeParams, myService) {
var my = this;
var sid;
myService.getInfo().success(function(data) {
$scope.id = data.id; // changed from my.id to $scope.id
//sid= my.id;
});
//my.id = sid;
});
})();
HTML
<div data-id="id"></div>

Updating the scope variable across multiple controllers in angularjs

I have two controllers- searchBoxController and productList. What I am trying to do is to update the scope variable $scope.products from multiple controllers. I know that defining it as a root variable is a very bad design- but putting that in shared service is not solving the problem. The update doesn't reflect in the HTML templates!
function SearchTermService(){
this.productSearch = function(data, $http){
var url = "";
$http.get(url).then(function(resp){
return resp.data;
},
function(err){
console.log(err);
});
};
};
var app = angular.module('app', []);
app.service("myService", MyService);
app.service("searchTermService", SearchTermService);
app.run(function($rootScope) {
$rootScope.products = new Date();
});
app.controller('productList', function ($scope, $rootScope, $http, myService) {
$rootScope.products = prod_res;
});
app.controller('searchBoxController', function($scope, $http, searchTermService, $rootScope){
$scope.getSearchResults = function(){
$rootScope.products = searchTermService.productSearch($scope.term, $http)
};
});
PS: I am not sure if I need to have a promise returned while assigning the $rootScope.products in 'searchBoxController', as the console.log says its undefined. Currently I am not returning a promise from the service.
In order to update a scope variable across multiple controller, you can use angular service.
You should use this because all angular services are singletons, so you can easily share common logic, share data between controller.
I've made an example where I use service in order to update some data. Then, my factory return an object data, so we will get an object, not just a fixed value. Thanks to this, our data will be updated, we will keep the binding data.
Controller
(function(){
function Controller($scope, $timeout, Service) {
//Retrieve current data object of our service
$scope.data = Service.value;
//will be set to 4
$timeout(function(){
Service.set(4, 'product');
}, 1000);
}
angular
.module('app', [])
.controller('ctrl', Controller);
})();
(function(){
function Controller2($scope, $timeout, Service) {
//Retrieve current data object of our service
$scope.data2 = Service.value;
}
angular
.module('app')
.controller('ctrl2', Controller2);
})();
Service
(function(){
function Service() {
//Our data object
var data = {
product: null
};
function set(value, field){
data[field] = value;
}
return {
set: set,
value: data
};
}
angular
.module('app')
.factory('Service', Service);
})();
HTML
<body ng-app='app'>
<div ng-controller='ctrl'>
<h2>Service value : {{data.product}}</h2>
</div>
<div ng-controller='ctrl2'>
<h2>Service value from controller2 : {{data2.product}}</h2>
</div>
</body>
So, we will share our data across multiple controller. By using services, you can avoid to use the $rootScope.
You can see the Working plunker

Resources