As the title says, I have a problem with reference switching.
My html:
div ng-repeat="data in parseurl">
{{data.url}}
</div>
In my JS code, I'm trying to do two things. The first step is to grab the data off a server and put it into an array (called allsongs). Afterwards, I parse the data and put it into another array (parseurl).
var app = angular.module("write", []);
app.controller("Ctrl", ['$scope', '$http', function($scope, $http){
$scope.allsongs = [];
$scope.parseurl = [];
$scope.getstuff = function(){
$http.get("my link here").then(function(response){
$scope.allsongs = response.data;
}); //step one -> this works!
$scope.parser(); //step two
};
$scope.parser = function()
{
for(i=0;i<$scope.allsongs.length;i++) {
for(var key in $scope.allsongs[i]) {
var value = $scope.allsongs[i][key];
var object = {Url : value.Url}; //this does contain the correct info I want
$scope.parseurl.push(object);
}
$scope.getstuff();
}]);
So what is happening is that, if I ng-repeat on allsongs, then I do get a bunch of un-parsed urls. But if I ng-repeat on parseurl, then I get nothing. Obviously the reference isn't changing, but how can I do it?
$scope.parser() needs to be called after the data was recived. Put it into your promise callback function like in the following example. Please note that $http is an asynchronous function. In that way $scope.parser() was executed before your request has been finished.
$scope.getstuff = function(){
$http.get("my link here").then(function(response){
$scope.allsongs = response.data;
$scope.parser();
});
};
Related
I am using a static json file to simulate my server and getting my array of orders from it.
I'm presenting the orders in a table in my html file with the option of deleting one from it.
Each time I load the html file the full list gets loaded, with the orders I have deleted throught the controller function.
How can I loat the data from the factory only once?
Here is my controller:
app.controller("MainPageCtrl", function($scope, getOrdersFactory)
{
$scope.orders = [];
// Getting the data frm the facrory
var dataPromise = getOrdersFactory.getDataFunc();
dataPromise.then(function(data){
$scope.orders = data.orders;
});
// Deletes an orders.
$scope.deleteOrder = function(order){
// Finds the index of the order.
var orderIndex = $scope.orders.indexOf(order);
// Delete the order.
$scope.orders.splice(orderIndex, 1);
};
});
By default angular services and factories are singletons(loaded only once). The problem you are facing is with controller re-initialization. When route change happens the controller is re-initialized so therby getting the previous value from the factory.
You can use a setter function on your 'getOrdersFactory'.
Assuming your 'getOrdersFactory' to be
app.factory('getOrdersFactory',function(){
//code to read from file and set the file on a variable orderDetails
var orderDetails = contentsReadFromFile;
return{
getDataFunc:function(){
return orderDetails
},
setDataFunc:function(modifiedOrderDetails){
orderDetails = modifiedOrderDetails;
//code to set the new content to the static file
}
}
}
code to read the file from the static file will be rendered when you inject the factory for the first time, and on your controller set the order details on the delete function
// Deletes an orders.
$scope.deleteOrder = function(order){
// Finds the index of the order.
var orderIndex = $scope.orders.indexOf(order);
// Delete the order.
$scope.orders.splice(orderIndex, 1);
getOrdersFactory.setDataFunc($scope.orders);
};
I guess you are losing your data i.e $scope.orders .If this is the scenario just change
dataPromise.then(function(data){
$scope.orders = data.orders;
});
to
dataPromise.then(function(data){
$scope.orders = angular.copy(data.orders);
});
I am working on an app that is supposed to filter and sort out data from two json files. The app will have two tables that compare and contrast this data using ngRepeat myData. So far, the top table is already requesting a json file:
app.controller('tableTopController', function ($scope, $http) {
$http.get('first.json').success(function(response){
$scope.myData = response; });
The bottom table is supposed to read data from my second json file: second.json.
Try using $q.all() to resolve both promises and execute a callback function when both are successful. For more info, see the docs.
var promises = [];
promises.push(getFirstJson());
promises.push(getSecondJson());
$q.all(promises).then(function (results) {
var firstJson = results[0];
var secondJson = results[1];
});
function getFirstJson() {
return $http.get(...);
}
function getSecondJson() {
return $http.get(...);
}
If you want to wait for the first call to complete before you get the second file and if you want to ensure everything is loaded before comparing and contrasting:
app.controller('theController', function ($scope, $http) {
$http.get('first.json').success(function(response){
$scope.firstData = response;
$http.get('second.json').success(function(response1){
$scope.secondData = response1;
//add any other logic you need to do here to compare & contrast
//or add functions to $scope and call those functions from gui
});
});
});
Or, call them sequentially but then you need to ensure your comparing and contrasting can't start until both are loaded:
app.controller('theController', function ($scope, $http) {
$http.get('first.json').success(function(response){
$scope.firstData = response;
});
$http.get('second.json').success(function(response1){
$scope.secondData = response1;
});
//add any other logic you need in functions here to compare & contrast
//and add those functions to $scope and call those functions from gui
//only enabling once both firstData and secondData have content
});
I have the following controller in my application, but there is some strange behaviour that I cannot explain. I've numbered two of the lines to help with the description, they don't both exist at the same time in the live code.
var app = angular.module('movieListings', ['ngResource', 'ngRoute', 'ui.bootstrap', 'ng']);
var cachedMovieList = [];
//Controller for movie list
app.controller('MovieListController', ['$http', function($http){
var mlc = this; //needed for the $http request
this.movies = cachedMovieList;
this.loaded = false;
this.error = false;
if(this.movies.length == 0) {
console.log("Grabbing new movie list from DB");
$http.get('data/movies.json').success(function(data){
mlc.movies = data;
mlc.loaded = true;
cachedMovieList = data; //(1)
}).error(function(data){
mlc.error = true;
});
cachedMovieList = this.movies; //(2)
} else {
this.loaded = true;
}
}]);
With the code as above with line (1) present and line (2) not present, I am able to cache the result so that when I flick between pages I don't need to constantly re-get the data.
However if I remove line (1) and insert line (2), the variable "cachedMovieList" is never populated. I would expect it to be based on the fact that "mlc.movies" was assigned to... but I cannot understand why this is the case?
Any advice welcome.
Implement a factory that retrieves the data. Use angular.copy to preserve the array reference when the data returns from the $http call.
var app = angular.module('movieListings', ['ngResource', 'ngRoute', 'ui.bootstrap', 'ng']);
app.factory('movies', function($http) {
var movies = {
data: [],
loaded: false,
error: false
};
$http.get('data/movies.json').success(function(data){
angular.copy(data, movies.data);
movies.loaded = true;
}).error(function(data){
movies.error = true;
});
return movies;
});
Inject the factory into your controller:
//Controller for movie list
app.controller('MovieListController', ['$scope','movies', function($scope, movies){
this.movies = movies;
}]);
Factories (like services) are singletons. They are initialized once, and cached for the entire lifetime of the SPA.
Use the controller in the view:
<div ng-controller="MovieListController as ctrl">
<div ng-show="!ctrl.movies.loaded"> Loading... </div>
<ul>
<li ng-repeat="movie in ctrl.movies.data">
{{ movie.name }}
</li>
</ul>
</div>
If I've understood this correct, you're entering the if condition only when this.movies.length == 0. In such a case, this.movies will be null, so cachedMovieList would get populated with a null value.
Because (2) probably gets executed first before the $http.get() request is finished. $http.get() is an AJAX request.
If you want to cache, you might want to use $cacheFactory instead :)
I believe you are mistaking the live updation of values that happens in view to live updation that would happen with variable assignments. Your line 2 will set cachedMovieList to [] initially. I believe that is quite obvious. But you think that since callback updates this.movies that change would cascade to cachedMovieList. That won't happen as you are re-assigning the mlc.movies variable that means it refer to new variable instead of modifying existing value.
If you really want to make you logic work, please update mlc.movies variables like following
mlc.length = 0 // Empty the array
mlc.push.apply(mlc, data);
Please check following answer for more information
How do I empty an array in JavaScript?
I am using ng-repeatto loop through the Rotten tomatoes api and display the movie title. This is the code I have
JS:
var app = angular.module('app', []);
app.controller('ApiCtrl', function($http){
var app = this;
var url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json"
var key = "?apikey=myKey"
$http.get(url+key)
.success(function(data) {
app.movies = data;
console.log(data);
})
})
HTML:
<li ng-repeat="movie in app.movies">
{{movie.title}}
</li>
</body>
This is outputting 3 blank li elements on the screen, if I call just {{movie}}then the entire object is outputted so I know the binding is correct.
An example of the JSON:
"movies": [
{
"id": "771315918",
"title": "Divergent",
}]
Where's your $scope?
Try something like:
var app = angular.module('app', []);
app.controller('ApiCtrl', function($scope, $http){
var url = "http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json"
var key = "?apikey=myKey"
$scope.movies = $http.get(url+key);
I'm not sure if the above code will work of $http. My suggestion is that before trying to get the data from a server, get all the angular stuff working. For instance, define $scope.movies like this:
$scope .movies = [
{
"id": "771315918",
"title": "Divergent",
}
];
first and get that working.
The rotten tomatoes API has it's own movies key, so I think you need to do:
.success(function(data) {
app.movies = data.movies;
}
$scope and 'this' don't necessarily refer to the same thing. I would do
$scope.app = null;
//When the deferred object is returned
.success(function (data) {
$scope.app = data;
});
By using 'this' you are referring to the controller but is not accessible by the view. Here is another post that is really helpful:
'this' vs $scope in AngularJS controllers
Everything works fine but I have problem getting source from service.
I have SERVICE code below.
app.factory('myService',
function($rootScope, ResourceData) {
var result = {};
var data = ResourceData.query();
result.getData = function() {
// problem here
}
return result;
});
And CONTROLLER contain code.
app.controller('myController', ['$scope', 'myService',
function myController($scope, myService) {
$scope.data = myService.getData();
});
My problem is if I have function in my SERVICE like this
result.getData = function() {
return data;
}
Everything works fine but I need to filter that data before I get it
If I change body like this I get an empty array the problem seems like it is from AngularJS.
If I create static array it works.
result.getData = function() {
var arr = [];
angular.forEach(data, function(item, key) {
// simple filter
if(item.ID > 10) {
return;
}
else {
arr.push(item);
}
});
return arr;
}
The result of "ResourceData.query()" is asynchronous:
When the data is returned from the server then the object is an instance of the resource class... It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
When the page first loads, I'm guessing that the controller runs before the data is returned from the server, so the first time getData() is called, data is probably not yet populated with any data, so you get an empty array.
One solution to your problem would be to filter the data in the view/HTML with an Angular filter, rather than in the service.
<div ng-repeat="item in data | filter:myFilter">
{{item.ID}}: {{item...}}
</div>
Then in your controller:
$scope.myFilter = function(item) {
return item.ID <= 10;
}