我有一个烦人的问题,我需要帮助。 我有一个控制器从雅虎股票中获取股票数据。控制器将数据存储在$ scope.stocks中,在我看来,我可以用ng-repeat显示数据,所以一切都很好。当我尝试从数据的每个元素中提取一些数据时,问题就来了......它说对象是未定义的。 下面是我的控制器进行提取。
app.controller('controller2', ['$scope','$resource', function($scope, $resource){
var URL='http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quote?format=json';
$scope.stockAPI=$resource(URL, {callback: 'JSON_CALLBACK'},{get:{method:'JSONP'}});
$scope.stocks=$scope.stockAPI.get({});
console.log($scope.stocks);
var temp=$scope.stocks.list.resources; // this returns an error (TypeError: Cannot read property 'resources' of undefined)
console.log(temp);
}]);
我使用此控制器的视图如下所示(此视图也显示了我想要的数据)
<body ng-app="weatherApp" class="container">
<div ng-controller="controller2" ng-model="buffer">
<h1>This is the index page where the application is mounted</h1>
<ul ng-repeat="stock in stocks.list.resources">
<li>{{stock.resource.fields.name}} {{stock.resource.fields.price}} {{buffer.push(stock.resource.fields.name)}}</li>
</ul>
</div>
</body>
我从控制器返回的json数据如下所示,并且视图可以正常渲染它,但是我不能创建一个新列表,其中只包含三个字段中包含的每个元素中包含的多个字段对象......请帮助这两天让我感到沮丧。
$ promise:d
$ resolved:true
list: Object
meta: Object
resources: Array[173]
[0 … 99]
[100 … 172]
length: 173
__proto__: Array[0]
__proto__: Object
proto :e
答案 0 :(得分:1)
您应该传递一个函数,然后在该函数中设置$scope.stocks
$scope.stockAPI.get({}, function(data){
$scope.stocks = data;
});
否则,您可以使用$promise
,然后在$scope.stocks
功能中更新.then
。
$scope.stockAPI.get().$promise.then(function(data){
$scope.stocks = data;
});
答案 1 :(得分:0)
好的,问题解决了。 如果您遇到类似的问题,这是如何解决的。 首先,实现http调用是异步完成的,第二次尝试使用服务来处理异步任务(或者一般是本地数据仓库)。 所以我们来看看细节;
var app=angular.module('app',[]);
app.service("DataService", function($http, $q){
var defered=$q.defer(); // this is not for the HTTP delay... instead it is for populating our local Names and Lengths variables --defined below
var buffer=[]; // I'm not sure if I need this anymore but It hold a promise as well
var Names=[]; // these are the variables I'm interested in using, which I first need to populate them from an http call that I'll call later
var Lengths=[]; // also this is a local variable that I want ( just for kicks)
var url='http://www.w3schools.com/angular/customers.php'; // ofcourse our remote server API that responds with a jason full of data
// this function is called from inside our fetchdata method defined below this method, this function processes the data (from the http promise once successfull)--- it just parses through the json objects and isolates/groups similar data --- all the names go into a name array and the length of each name goes into a different array ( I want to make a D3 chart from it in the end)
var fixup= function(data){
var records=data.records; // records now contains an array of objects with few fields each
records.forEach(function(record){
console.log(record.Name+" ---- "+record.Name.length); // taking a look/peak at the individual records fields
Names.push(record.Name); // store each record's name value in our local Names array
Lengths.push(record.Name.length); // do something similar for the length of each name
})
defered.resolve(Names);// this is the main thing here-- you will send our local Names array once everything works out- i.e the data has arrived from the server and the loop is finished running processing the fetched data... when you return the promise (as we will see later) it will contain whatever we put the resolve as an argument so here it is Names array, it could be whatever you want
} // so that is it for fixdup function
// next is our fetching method
var fetchData=function(){
$http({ // this is an asynch call, it moves on to the next method once the call is made-- so you have no data still.
method: 'GET',
url: url
}).success(function(data){ // this is the next big deal here the promise (internally used by the http service) is processed here- if successful this function handles the response if not the next method handles the errors
buffer=fixup(data);// give the data to our fixup function we saw above
}).error(function(err, status){
console.log(err);
})
}// so anyone that looks at buffer will not see anything unless the .then method of this promise object is invoked
console.log('fetching data away we goooo....'); // lets us know where we are at the console logs
fetchData(); // does the fetching business which calls the fixup method which calls defered.resolve() method.
return defered.promise; // this will wait untill we're done with defered.resolve(Names) call... this returns a promise that we will have our names array sometime later
});
// here we are going to use our dataservice service we defined above... remember it will only five us something once the resolve(names) finishes running
app.controller("controller1",['$scope', 'DataService', function($scope, DataService){
//$scope.myData=[];
$scope.names=[]; // these guys are clue less about where their data is coming from, so they are just chilling here in the scope unaware of what's about to happen
$scope.lengths=[]
DataService // kapow!! we call our get-us-some-data service happily named DataService ofcourse
.then(function(names){ // so this function is fired up once we have names parameter available--- this is sent from the last call in the DataService service (return defered.promise) which as we discussed will only run when the resolve(Names) is done running ... I know it sounds confusing but it will take you few tries to get a hung of it--- took me two long days to rap my mind about this asynch thing --- I'm too synch to a fault haha OK moving on
console.log('back from DataService sendit service method'); // inspect our efforts here... first let us know where we are when we get an output on the console
$scope.names=names; // here is the magic... after all those promises and and back and forth method calling we end up with out own local scope names array exactly like we wanted and we can give this data to a D3 directive and everyone is happy
console.log(names);
})
.then(function(names){ // we can chain promises and do other things here, I'm populating another local scope variable from the same promise returned... so we will not need to call fetch data again we have our own clean data here in our controller... also I would like to make it better by putting this part in the service inside a wrapper that looks if the local data is empty call fetchdata and follow the same steps else return the populated local data (local to the service) and many controller can now have access to the same data as it should be
$scope.names.forEach(function(name){$scope.lengths.push(name.length);})
console.log($scope.lengths);
});
}]);
// I hope this helpes people new to the whole promises and asynch methods in general
如果我在任何地方理解错误,请告诉我,因为我还在学习这种异步方法,我将非常感激。
<!Doctype HTML>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- Angular JS library-->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script type="text/javascript" src="https://code.angularjs.org/1.4.3/angular-resource.min.js"></script>
<script type="text/javascript" src="https://code.angularjs.org/1.4.3/angular-route.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<!-- D3.js library -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script type="text/javascript" src="app.js"></script>
</head>
<body ng-app="app" class="container">
<div ng-controller="controller1">
<div ng-repeat="n in names">
{{n}}-------{{lengths[$index]}}
</div>
</div>
</body>
这是我用来查看范围的index.html 它像魔术一样......如果有人对我和D3结合感兴趣,请告诉我我会把它包含在这里。 后来的人。