i have a problem with an http.get.
Index.html
<div ng-repeat="element in elements">
<p>{{element.elementText}}</p>
</div>
app.js
I have two controllers. First one initialize $scope.elements with a json and works:
$http.get('someUrl')
.success(function (response) {
$scope.elements = response;
})
Seconde one update $scope.elements with a another json when a scope function is called by ng-click:
$scope.updateScope = function () {
$http.get('someOtherUrl')
.then(function (response) {
$scope.elements = response.data;
});
But when i call updateScope nothing appens. I try use .success but nothing. I try using $scope.$apply after assign response to $scope.elements but it generates an error (Error: [$rootScope:inprog] http://errors.angularjs.org/1.3.11/$rootScope/inprog?p0=%24digest).
UPDATE -
If I reload page ng-repeat on scope element works correctly.
So $scope.elements contains right values but ng-repeat doesn't update itself.
Sorry for my english...
Could you help me please?
.then(function (response) { and .success(function (response) { gets different objects in their callbacks. In the first case you get the response's data directly, in second it will be wrapped in an object (that has also other properties - like status, config, statusText, and so on).
If you use .then your response's body will be in sth.data, not in sth. So in your case:
$scope.updateScope = function () {
$http.get('someOtherUrl').then(function (response) {
$scope.elements = response.data;
});
You can use angular.merge
angular.merge(object1, object2)
To share data you want to use a service, not root scope. Consider an example like this:
HTML
<div ng-app="app">
<div ng-controller="controller1 as vm">
<input type="text" ng-model="vm.dataService.data" />{{vm.dataService.data}}</div>
<div ng-controller="controller2 as vm">
<input type="text" ng-model="vm.dataService.data" />{{vm.dataService.data}}</div>
</div>
JS
var app = angular.module('app', []);
app.factory('DataService', function () {
var data;
return {
data: 'Hello, World!'
};
});
app.controller('controller1', function (DataService) {
var vm = this;
vm.dataService = DataService;
});
app.controller('controller2', function (DataService) {
var vm = this;
vm.dataService = DataService;
});
Here is a jsFiddle that runs that code.
you can try following code.(you need to include $timeout)
$scope.updateScope = function () {
$http.get('someOtherUrl')
.then(function (response) {
$scope.elements = response;
$timeout(function(){
$scope.$apply();
});
});
Related
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>
I've started doing Angular for three days now and I can't wrap my head around the concept of promise.
I'm trying to create a factory to share JSON data between two controllers. The data represent a serialized SQL datatable.
The factory fetches the data using $http
var app = angular.module('myApp', ['ngAnimate', 'ngSanitize', 'ui.bootstrap']);
app.factory('Tableau', function ($http, $q) {
var obj = {};
obj.getTable = function (page) {
var temp = {};
var defer = $q.defer();
$http.get('api/Table/' + page).then(function (resolve) {
defer.resolve(resolve.data);
});
return defer.promise;
}
return obj;
});
The first controller should display the data as an HTML table
app.controller("TableController", function ($scope, Tableau) {
$scope.elements = Tableau.getTable(2); // get the first ten rows with row id >= n x 10 (in this case 2 x 10)
});
And here's the HTML code with the ng directives
<tr ng-repeat="t in elements.myarray track by $index">
<td ng-repeat="(k,v) in t track by $index">
<div ng-if="k.indexOf('#')===0">
<span class="label label-default" ng-repeat="vv in v.split(';')">{{vv}}</span><br />
</div>
<div ng-if="k.indexOf('§')===0">
Lien
</div>
<div ng-if="k.indexOf('#')!=0 && k.indexOf('§')!=0">
{{v}}
</div>
</td>
</tr>
I have no problem calling $http from the controller, but when I moved the code to the factory, $scope.elements contains a promise object instead of my expected JSON object.
I did not implement the second controller, which would create a pagination for the table (using ui-bootstrap)
How can I wait for $http to complete before returning returning an object from the factory ?
If this isn't possible, how can I share data retrieved from a server in a single move ?
Thanks in advance.
You need to wait for the promise to complete before using its result. That means using .then():
app.controller("TableController", function ($scope, Tableau) {
Tableau.getTable(2)
.then(function (result) {
$scope.elements = result;
});
});
You've also fallen prey to the Explicit Promise Construction Antipattern.
Simpler implementation for your factory:
app.factory('Tableau', function ($http, $q) {
var obj = {};
obj.getTable = function (page) {
return $http.get('api/Table/' + page)
.then(function (result) {
return result.data;
});
};
return obj;
});
In your controller:
Tableau.getTable(2)
.then((data) => {
$scope.elements = data
})
I've a action method Index inside UserController inside admin area as below:
My angular code is:
var app = angular.module('myAppS', []);
app.controller("myController", function ($scope, $http) {
$scope.myVal = "Hello Angular JS";
$scope.myFunc = function () {
alert('Hi');
$http.get('/Admin/User/Index').then(function (response) {
$scope.MyValue = response.data;
});
};
});
my html code is:
<div ng-controller="myController">
{{myVal}}
<input type="button" value="Get" ng-click="myFunc()" width="45%" />
</div>
When I click get button only alert function gets executed but I cannot make call to server.
$http.get('/Admin/User/Index').then(function(response)
{
$scope.MyValue = response.data;
}, function(error)
{
console.log(error);
console.log("You should get the error here")
});
Use this code by itself to see if the $http.get(..) works, then you can put it into myfunc
I have the following HTML structure:
<div ng-controller="MainController">
<div ng-repeat="row in rows">
[[row.id]]
</div>
<div ng-controller="SubController">
<div ng-repeat="row in rows">
[[row.id]]
</div>
</div>
</div>
Angular code is:
myApp.controller('MainController', function ($scope, $http) {
$http.get('/foo/ajaxGetSomeData/').then(function (response) {
$scope.rows = response.data;
});
});
myApp.controller('SubController', function ($scope, $http) {
$http.get('/bar/ajaxGetAnotherThing/').then(function (response) {
var parentRows = $scope.$parent.rows;
var newRows = parentRows.merge(response.data);
$scope.rows = newRows;
});
});
The problem here is that sometimes the first request executes after the second. And the second depends on the first, so I'm getting an error.
How could I solve this?
Below elaborates a bit more on my comment. Here we would initialize both promises inside the DataRows service (through call to initData from MainController). The SubController is no longer dependent on MainController, but just the fact that something else has called initData. If something else hasn't called that function, then you will get console errors for calling "then" on undefined object.
I also used $timeout instead of $http to mock out async work. I don't know what your data looks like, so I just made an array of strings, you should be able to adapt.
angular.module('myApp', [])
// Using $timeout instead of $http for demo
.service('DataRows', function ($http, $q, $timeout) {
var someData,
anotherThing;
this.initData = function () {
// actual call. get rid of $timeout line in actual code
// someData = $http.get('/foo/ajaxGetSomeData/').then(function (response) {
someData = $timeout(function () { return {data: ['parentRow1', 'parentRow2', 'parentRow3']}; }, 1500).then(function (response) {
return response.data;
});
anotherThing = someData.then(function (parentRows) {
// actual call. get rid of $timeout line in actual code
// return $q.all([parentRows, $http.get('/bar/ajaxGetAnotherThing/')]);
return $q.all([parentRows, $timeout(function () {return {data: ['childRow1', 'childRow2', 'childRow3']}}, 1500)]);
}).then(function (promises) {
var parentRows = promises[0],
response = promises[1];
// from your original code -- merge is not available here. Mocking concatted rows from first call
// return parentRows.merge(response.data);
return parentRows.concat(response.data);
});
};
this.getSomeData = function () {
return someData;
};
this.getAnotherThing = function () {
return anotherThing;
};
})
.controller('MainController', function ($scope, DataRows) {
// initData first so both promises are ready
DataRows.initData();
// getSomeData is the first promise (call to /foo/ajaxGetSomeData)
DataRows.getSomeData().then(function (rows) {
$scope.rows = rows;
});
})
.controller('SubController', function ($scope, DataRows) {
// getAnotherThing is the second promise that depends on the first (/bar/ajaxGetAnotherThing)
DataRows.getAnotherThing().then(function (newRows) {
$scope.rows = newRows;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainController">
<div ng-repeat="row in rows">
{{row}}
</div>
<div ng-controller="SubController">
<div ng-repeat="row in rows">
{{row}}
</div>
</div>
</div>
I am newbie to angular and I am fetching data from json file using a service and then returning the data to controller. When i click the button the controller method is not getting executed and there are no errors in console.log. what am i missing here?
My service code:
Service.js
app.factory('MovieService', function ($http) {
var url = "js/data.json";
var data;
return {
getData: function() {
return $http.get(url)
.success(function(response) {
data = response;
return data;
})
.error(function (error){
console.log("error");
})
}
};
});
Controller.js
app.controller('MainController1', ['$scope', '$log','$location','MovieService', function($scope,$log,$location,MovieService) {
console.log("click");
var getData = function() {
// This service's function returns a promise
MovieService.getData()
.then(function(data) {
// promise fulfilled
console.log("controller data");
$scope.custdata = data;
console.log($scope.custdata);
}, function(error) {
// promise rejected, could log the error with:
console.log("error");
});
};
}])
index.html
<div class="main" ng-controller="MainController1 as main">
<input type="button" name="getdata" value ="Get data" ng-click="main.getData ()"></input>
</div>
data
[
{
"Id": "1",
"Name": "Harry Potter"
},
{
"Id": "2",
"Name": "Jurassic Park"
}
]
You need to bind controller function on scope.
$scope.getData = function() { }"
instead
var getData = function() { }
and call it in template like
ng-click="getData ()"
You are using the controller as alias syntax.
In this case, your controller functions that need to be accessed from the view should be assigned to this.
So, define your function as a property of this and not as an independent function - like so:
this.getData = function () {...}
You are using var getData which will make the function a local function and not expose it.
Few things should be notice:-
1) You should use this instead of var to bind the function to the controller in controller as syntax:-
this.getData = function() {//your logic}
2) You are wrapping promise twice first in success() or error() then in another then() function instead do it like this:-
In service:-
getData: function() {
return $http.get(url);
}
In controller:-
MovieService.getData()
.then(function(response) {
// promise fulfilled
console.log("controller data");
$scope.custdata = response.data;
console.log($scope.custdata);
}, function(error) {
// promise rejected, could log the error with:
console.log("error");
});
3) <input> should not close like </input> it is not having closing tag.
Hope it help :)
PLUNKER