var app = angular.module('app',['ui.bootstrap']);
app.controller("ListCtrl", function ($scope, $http) {
$scope.submit = function () {
$scope.loading = true;
$scope.error = false;
$http.get('http://www.omdbapi.com/?s=' + $scope.search + '&r=json')
.then(function (res) {
var titles = [];
angular.forEach(res.data.Search, function(item){
$http.get('http://www.omdbapi.com/?t=' + item.Title + '&y=&plot=full&r=json').then(function(res){
if (res.data.Poster === "N/A") {
res.data.Poster = "http://placehold.it/350x450/FF6F59/FFFFFF&text=Image+not+Available!!";
}
titles.push(res.data);
});
});
$scope.movie = titles;
$scope.results = true;
$scope.error = false;
$scope.loading = false;
if (titles.length==0) { // not working
$scope.results = false;
$scope.error = true;
}
})
I have been tried several things like :
我尝试过以下几件事:
Object.getOwnPropertyNames(titles).length === 0)
obj == null
None of them seems to work...
它们似乎都不起作用……
4 个解决方案
#1
0
$http.get()
is async so the statement if (titles.length==0) {
gets executed right away.
$http.get()是异步的,因此if (titles.length= 0){的语句将立即执行。
Have a counter to determine when all the Promises get resolved and then perform the check. Move the if statement inside the callback.
有一个计数器来确定所有的承诺何时得到解决,然后执行检查。在回调中移动if语句。
var count = res.data.Search.length;
angular.forEach(res.data.Search, function(item){
$http.get('http://www.o....rest of code').then(function(res) {
// rest of code
titles.push(res.data);
if (!count-- && !titles.length) {
$scope.results = false;
$scope.error = true;
}
}
});
});
#2
2
This is happening because of incorrect scope:
这是由于不正确的范围:
var titles = [];
is defined inside the .then
var标题=[];是在里面定义的吗?
and you are checking the length outside of .then
你要检查
since titles
is not available outside .then
it would not work. (undefined.length==0
)
因为在外面没有头衔,所以不能用。(undefined.length = = 0)
Solution:
解决方案:
.then(function (res) {
var titles = [];
angular.forEach(res.data.Search, function(item){
$http.get('http://www.omdbapi.com/?t=' + item.Title + '&y=&plot=full&r=json').then(function(res){
if (res.data.Poster === "N/A") {
res.data.Poster = "http://placehold.it/350x450/FF6F59/FFFFFF&text=Image+not+Available!!";
}
titles.push(res.data);
});
$scope.movie = titles;
$scope.results = true;
$scope.error = false;
$scope.loading = false;
if (titles.length==0) { // now this will work
$scope.results = false;
$scope.error = true;
}
});//titles will not be available after this.
#3
0
In your case, the check
在你的情况下,检查。
titles.length
will be executed before the
会在之前执行吗
titles.push
because you use an asynchronous request which will return later. You need to wrap your statements into the answer-block of the request.
因为您使用的是稍后返回的异步请求。您需要将语句封装到请求的应答块中。
#4
0
Just as an aside, but beneficial for my practice and your future help:
顺便说一句,但对我的实践和你未来的帮助是有益的:
Part of the problem you were having was scope-management (JS-scope, not Angular $scope), part of it was concurrency-management, and part of it appeared to be plain old scope-formatting making it hard to see where all control blocks start and end (that gets miserable when it's not just if/else, but with callbacks/promises, too).
问题的一部分你在范围管理(JS-scope,不是角范围美元),这是并发管理的一部分,它的一部分似乎是普通scope-formatting很难看到,所有控制块的开始和结束(被痛苦的时候不仅if / else,但回调/承诺,)。
This is a small example of how you might consider tackling these problems, through a quick refactor of your issues:
这是一个小例子,说明你如何考虑通过快速重构你的问题来解决这些问题:
function pluck (key) {
return function pluckFrom(obj) { return obj[key]; };
}
angular.module("app", ["ui.bootstrap"]);
angular.moule("app").service("omdbService", ["$http", function ($http) {
function getSearch (search) {
var searching = $http.get("http://www.omdbapi.com/?s=" + search + "&r=json")
.then(pluck("data"));
return searching;
}
function getMovie (title) {
var searching = $http.get("http://www.omdbapi.com/?t=" + title + "&y=&plot=full&r=json")
.then(pluck("data"));
return searching;
}
return {
getSearch: getSearch,
getMovie: getMovie,
getPlaceholderPoster: function () { return "http://placehold.it/350x450/FF6F59/FFFFFF&text=Image+not+Available!!"; }
};
}]);
angular.moule("app").controller("ListCtrl", ["$scope", "$q", "omdbService", function ($scope, $q, omdb) {
function loadMovie (movie) {
return omdb.getMovie(movie.Title)["catch"](function () { return undefined; });
}
function movieExists (movie) { return !!movie; }
function updatePoster (movie) {
movie.Poster = movie.Poster || omdb.getPlaceholderPoster();
return movie;
}
function setResults (movies) {
$scope.movie = movies; // $scope.movies, instead?
$scope.results = true;
$scope.error = false;
$scope.loading = false;
}
function handleError () {
$scope.results = false;
$scope.error = true;
}
$scope.submit = function () {
$scope.loading = true;
$scope.error = false;
omdb.getSearch($scope.search)
.then(pluck("Search"))
.then(function (movies) { return $q.all(movies.map(loadMovie)); })
.then(function (movies) { return movies.filter(movieExists).map(updatePoster); })
.then(setResults, handleError);
};
}]);
There are 8000 valid ways of handling this, and everyone will see it a little differently.
This is also not really how I'd tackle it in production, but not too far off...
有8000种有效的处理方法,每个人都会有不同的看法。这也不是我在生产中如何处理它的方法,但也不是太离谱……
Moving all endpoint-calls out to a service which is responsible for those means that any controller in your system (with that module as a dependency) can access them.
将所有endpoint调用移动到负责这些的服务,这意味着系统中的任何控制器(以该模块作为依赖项)都可以访问它们。
Doing small things per function and letting Array.prototype methods do the iterating (IE8 can be shimmed if needed) means that each function is super-specific.
每个函数做小事情,让数组。原型方法进行迭代(IE8可以在需要的时候闪烁)意味着每个函数都是超级特定的。
By wrapping the controller/service functions in arrays, and naming their dependencies, they're now minification friendly.
通过将控制器/服务函数封装到数组中,并命名它们的依赖项,它们现在变得更小了。
The body of submit()
is less than 10 lines, and deals with all kinds of crazy async stuff, but I know that I've handled errors like one of the movies returning a 404 (my code should still fire, with the remaining movies, the code of others might not -- most code would either never trigger success or would fail all the way through the program, if the server threw an error for a movie). Now, I'm not checking that the server is sending the right kind of data for a "movie", but that's different.
提交()的身体小于10行,并处理各种异步疯狂的东西,但我知道我喜欢的一个电影返回一个404错误处理(我的代码应该还火,剩下的电影,其他人的代码可能不——大多数代码将不会触发成功或失败在整个程序中,如果服务器抛出一个错误的电影)。现在,我并没有检查服务器是否为“电影”发送了正确的数据,但这是不同的。
#1
0
$http.get()
is async so the statement if (titles.length==0) {
gets executed right away.
$http.get()是异步的,因此if (titles.length= 0){的语句将立即执行。
Have a counter to determine when all the Promises get resolved and then perform the check. Move the if statement inside the callback.
有一个计数器来确定所有的承诺何时得到解决,然后执行检查。在回调中移动if语句。
var count = res.data.Search.length;
angular.forEach(res.data.Search, function(item){
$http.get('http://www.o....rest of code').then(function(res) {
// rest of code
titles.push(res.data);
if (!count-- && !titles.length) {
$scope.results = false;
$scope.error = true;
}
}
});
});
#2
2
This is happening because of incorrect scope:
这是由于不正确的范围:
var titles = [];
is defined inside the .then
var标题=[];是在里面定义的吗?
and you are checking the length outside of .then
你要检查
since titles
is not available outside .then
it would not work. (undefined.length==0
)
因为在外面没有头衔,所以不能用。(undefined.length = = 0)
Solution:
解决方案:
.then(function (res) {
var titles = [];
angular.forEach(res.data.Search, function(item){
$http.get('http://www.omdbapi.com/?t=' + item.Title + '&y=&plot=full&r=json').then(function(res){
if (res.data.Poster === "N/A") {
res.data.Poster = "http://placehold.it/350x450/FF6F59/FFFFFF&text=Image+not+Available!!";
}
titles.push(res.data);
});
$scope.movie = titles;
$scope.results = true;
$scope.error = false;
$scope.loading = false;
if (titles.length==0) { // now this will work
$scope.results = false;
$scope.error = true;
}
});//titles will not be available after this.
#3
0
In your case, the check
在你的情况下,检查。
titles.length
will be executed before the
会在之前执行吗
titles.push
because you use an asynchronous request which will return later. You need to wrap your statements into the answer-block of the request.
因为您使用的是稍后返回的异步请求。您需要将语句封装到请求的应答块中。
#4
0
Just as an aside, but beneficial for my practice and your future help:
顺便说一句,但对我的实践和你未来的帮助是有益的:
Part of the problem you were having was scope-management (JS-scope, not Angular $scope), part of it was concurrency-management, and part of it appeared to be plain old scope-formatting making it hard to see where all control blocks start and end (that gets miserable when it's not just if/else, but with callbacks/promises, too).
问题的一部分你在范围管理(JS-scope,不是角范围美元),这是并发管理的一部分,它的一部分似乎是普通scope-formatting很难看到,所有控制块的开始和结束(被痛苦的时候不仅if / else,但回调/承诺,)。
This is a small example of how you might consider tackling these problems, through a quick refactor of your issues:
这是一个小例子,说明你如何考虑通过快速重构你的问题来解决这些问题:
function pluck (key) {
return function pluckFrom(obj) { return obj[key]; };
}
angular.module("app", ["ui.bootstrap"]);
angular.moule("app").service("omdbService", ["$http", function ($http) {
function getSearch (search) {
var searching = $http.get("http://www.omdbapi.com/?s=" + search + "&r=json")
.then(pluck("data"));
return searching;
}
function getMovie (title) {
var searching = $http.get("http://www.omdbapi.com/?t=" + title + "&y=&plot=full&r=json")
.then(pluck("data"));
return searching;
}
return {
getSearch: getSearch,
getMovie: getMovie,
getPlaceholderPoster: function () { return "http://placehold.it/350x450/FF6F59/FFFFFF&text=Image+not+Available!!"; }
};
}]);
angular.moule("app").controller("ListCtrl", ["$scope", "$q", "omdbService", function ($scope, $q, omdb) {
function loadMovie (movie) {
return omdb.getMovie(movie.Title)["catch"](function () { return undefined; });
}
function movieExists (movie) { return !!movie; }
function updatePoster (movie) {
movie.Poster = movie.Poster || omdb.getPlaceholderPoster();
return movie;
}
function setResults (movies) {
$scope.movie = movies; // $scope.movies, instead?
$scope.results = true;
$scope.error = false;
$scope.loading = false;
}
function handleError () {
$scope.results = false;
$scope.error = true;
}
$scope.submit = function () {
$scope.loading = true;
$scope.error = false;
omdb.getSearch($scope.search)
.then(pluck("Search"))
.then(function (movies) { return $q.all(movies.map(loadMovie)); })
.then(function (movies) { return movies.filter(movieExists).map(updatePoster); })
.then(setResults, handleError);
};
}]);
There are 8000 valid ways of handling this, and everyone will see it a little differently.
This is also not really how I'd tackle it in production, but not too far off...
有8000种有效的处理方法,每个人都会有不同的看法。这也不是我在生产中如何处理它的方法,但也不是太离谱……
Moving all endpoint-calls out to a service which is responsible for those means that any controller in your system (with that module as a dependency) can access them.
将所有endpoint调用移动到负责这些的服务,这意味着系统中的任何控制器(以该模块作为依赖项)都可以访问它们。
Doing small things per function and letting Array.prototype methods do the iterating (IE8 can be shimmed if needed) means that each function is super-specific.
每个函数做小事情,让数组。原型方法进行迭代(IE8可以在需要的时候闪烁)意味着每个函数都是超级特定的。
By wrapping the controller/service functions in arrays, and naming their dependencies, they're now minification friendly.
通过将控制器/服务函数封装到数组中,并命名它们的依赖项,它们现在变得更小了。
The body of submit()
is less than 10 lines, and deals with all kinds of crazy async stuff, but I know that I've handled errors like one of the movies returning a 404 (my code should still fire, with the remaining movies, the code of others might not -- most code would either never trigger success or would fail all the way through the program, if the server threw an error for a movie). Now, I'm not checking that the server is sending the right kind of data for a "movie", but that's different.
提交()的身体小于10行,并处理各种异步疯狂的东西,但我知道我喜欢的一个电影返回一个404错误处理(我的代码应该还火,剩下的电影,其他人的代码可能不——大多数代码将不会触发成功或失败在整个程序中,如果服务器抛出一个错误的电影)。现在,我并没有检查服务器是否为“电影”发送了正确的数据,但这是不同的。