Angular ui-router get asynchronous data with resolve - angularjs

I want to display a form with data corresponding to the edited item. I use ui-router for routing. I defined a state:
myapp.config(function($stateProvider) {
$stateProvider.
.state('layout.propertyedit', {
url: "/properties/:propertyId",
views : {
"contentView#": {
templateUrl : 'partials/content2.html',
controller: 'PropertyController'
}
}
});
In PropertyController, I want to set $scope.property with data coming from the following call (Google Cloud Endpoints):
gapi.client.realestate.get(propertyId).execute(function(resp) {
console.log(resp);
});
I don't know if I can use resolve because the data are returned asynchronously. I tried
resolve: {
propertyData: function() {
return gapi.client.realestate.get(propertyId).execute(function(resp) {
console.log(resp);
});
}
}
First issue, the propertyId is undefined. How do you get the propertyId from the url: "/properties/:propertyId"?
Basically I want to set $scope.property in PropertyController to the resp object returned by the async call.
EDIT:
myapp.controller('PropertyController', function($scope, , $stateParams, $q) {
$scope.property = {};
$scope.create = function(property) {
}
$scope.update = function(property) {
}
function loadData() {
var deferred = $q.defer();
gapi.client.realestate.get({'id': '11'}).execute(function(resp) {
deferred.resolve(resp);
});
$scope.property = deferred.promise;
}
});

You need to read the docs for resolve. Resolve functions are injectable, and you can use $stateParams to get the correct value from your routes, like so:
resolve: {
propertyData: function($stateParams, $q) {
// The gapi.client.realestate object should really be wrapped in an
// injectable service for testability...
var deferred = $q.defer();
gapi.client.realestate.get($stateParams.propertyId).execute(function(r) {
deferred.resolve(r);
});
return deferred.promise;
}
}
Finally, the values for resolve functions are injectable in your controller once resolved:
myapp.controller('PropertyController', function($scope, propertyData) {
$scope.property = propertyData;
});

I think your controller function needs $stateParams parameter from which you can get your propertyId. Then you can use $q parameter and create promise to set $scope.property with something like this:
var deferred = $q.defer();
gapi.client.realestate.get(propertyId).execute(function(resp) {
deferred.resolve(resp);
});
$scope.property=deferred.promise;
Here is description of using promises for handling async calls.

Try this easy way to use resolve in proper way
State code:
.state('yourstate', {
url: '/demo/action/:id',
templateUrl: './view/demo.html',
resolve:{
actionData: function(actionData, $q, $stateParams, $http){
return actionData.actionDataJson($stateParams.id);
}
},
controller: "DemoController",
controllerAs : "DemoCtrl"
})
In the above code I am sending parameter data which I am sending in the url,For examples if i send like this /demo/action/5
this number 5 will go to actionData service that service retrieve some json data based on id.Finally that data will store into actionData You can use that in your controller directly by using that name
Following code return some JSON data based on id which iam passing at state level
(function retriveDemoJsonData(){
angular.module('yourModuleName').factory('actionData', function ($q, $http) {
var data={};
data.actionDataJson = function(id){
//The original business logic will apply based on URL Param ID
var defObj = $q.defer();
$http.get('demodata.json')
.then(function(res){
defObj.resolve(res.data[0]);
});
return defObj.promise;
}
return data;
});
})();

How about this:
function PropertyController($scope, $stateParams) {
gapi.client.realestate.get($stateParams.propertyId).execute(function(resp) {
$scope.property = resp;
});
}

Related

AngularJS : Initialize service with asynchronous data for Multiple Controllers

For the subject matter, I found this SO post: Initialize service with asynchronous data
While this looks good, it is two years old and some of the references are out of date. Ex:
$http.get('url').success replaced with $http.get('url').then
Anyway, I have my model:
app.factory('User', function($http, $q) {
var myData = null;
var promise = $http.get('data.json').then(function (data) {
myData = data;
});
return {
promise: promise,
setData: function (data) {
myData = data;
},
doStuff: function () {
return myData.getSomeData();
}
};
});
and I need to share it across multiple controllers:
app.controller('controllerOne', function(User) {
// do stuff
});
app.controller('controllerTwo', function(User) {
// do stuff
});
app.controller('controllerThree', function(User) {
// do stuff
});
and each controller called from ngRoute:
app.config(function($routeProvider) {
$routeProvider
.when("/one",{,
controller: "controllerOne"
})
.when("/two",{
controller: "controllerTwo"
})
.when("/three",{
controller: "controllerThree"
});
});
... in no particular order
Now, there are a lot of posts that reference angular-deferred-bootstrap, but that library has not been updated since 2015. My question: Is angular-deferred-bootstrap still the preferred method to do this, or is there another / better way?

Accessing resolve object in controller

I am pulling back some route dependent data and the JSON is returned just fine from the server, but I am unsure how to actually access the object once I am in my controller. I have tried a few different things, such as putting the .then() inside the resolve, but that did not work.
resolve: {
menus: function ($http) {
var httpSource = this.httpSource = location.protocol + '//' + location.hostname;
const url = `${this.httpSource}/api/package/menus`;
return $http.get(url);
}
}
I did also try this
resolve: {
menus: function ($http) {
var httpSource = this.httpSource = location.protocol + '//' + location.hostname;
const url = `${this.httpSource}/api/package/menus`;
var menuData;
$http.get(url).then(response => {
menuData = response.data.Data;
})
return menuData;
}
}
I just simply cannot figure out how to load it into a controller property.
I tried to follow this, but the variable is not injected in the constructor -- https://medium.com/opinionated-angularjs/advanced-routing-and-resolves-a2fcbf874a1c#.2xzq32cwo
I attempt to load it with
this.menuData = $state.current.resolve.menus;
And I end up with this object.
"$http", function $stateProvider.state.state.resolve.menus($http)]
I am sure there is something fundamental I am missing here, but being new to Angular, I do not see it. Basically, my object is the full function definition and not the return data.Data.
My controller constructor.
static $inject = ['PackageService', '$stateParams', '$state', 'menus'];
constructor(packageService: Service.IPackageService, $stateParams, $state, DTOptionsBuilder, DTColumnDefBuilder, public logger: ILogger, public menus: any) {
There is a working example
This should be our controller:
namespace myNamespace
{
export class MyController
{
public MenuData: any[];
// strict notation support, for minification
static $inject = ['$scope', 'menus'];
// here we will get the resolved menus
constructor(
protected $scope: ng.IScope,
protected menus: ng.IHttpPromiseCallbackArg<any>)
{
this.MenuData = menus.data
}
}
}
And this is our state
.state('home', {
url: "/home",
templateUrl: 'template.html',
controller: myNamespace.MyController,
controllerAs: 'Ctrl',
resolve: {
// real example returning some data from data.json
menus: function ($http) {
var url = "data.json";
return $http.get(url);
}
}
})
And now we can consume the above in the template
<pre>{{Ctrl.MenuData | json }}</pre>
Check it here in action
I don't totally understand the way you're using your resolve, but here's a simple example of a way I did it recently:
In my Service:
myApp.service('mainService', function ($http, $q) {
this.getStarWarsData = function() {
var myPromise = $q.defer();
$http({
method: "GET",
url: "http://swapi.co/api/people/"
}).then(function(response) {
var parsedResponse = response.data.results; //Your code will be different here depending on the object you're getting back
console.log(parsedResponse);
console.log("this is the type of the pr", typeof(parsedResponse))
//this bit below is just manipulating the parsed response to obtain the data I wanted
var emptyArr = [];
for(var i = 0; i < parsedResponse.length; i++) {
emptyArr.push({
Name: parsedResponse[i].name,
Eyes: parsedResponse[i].eye_color,
})
} myPromise.resolve(emptyArr);
})
return myPromise.promise;
}
})
And Controller
myApp.controller("myController", ["$scope", "mainService", function($scope, mainService){
$scope.getData = function() {
mainService.getStarWarsData()
.then(function(response){
console.log("this is a response in our controller", response)
$scope.peoples = response;
})
}
}]);

Passing in a service to ui-router's resolve to avoid making $http requests

I am getting more familiar with ui-router and using .then as opposed to .success. However, I am having some difficulty passing in a service to resolve. Currently, resolve is blocking access to the controller. My goal is to get individual information from each user when they are selected.
I referenced the resolve through the ui-router wiki https://github.com/angular-ui/ui-router/wiki#resolve . Translations 2 seems to resemble how I am using my service
(function() {
'use strict';
angular
.module('app.orders')
.config(config);
function config($stateProvider) {
$stateProvider
.state('orders',{
url:'/customers:customerId',
templateUrl: './components/orders/orders.html',
controller: 'OrdersController',
controllerAs: 'ctrl',
resolve: {
customerFactory: 'customerFactory',
customerId: function( $stateParams, customerFactory) {
return customerFactory.getCustomers($stateParams.id);
}
}
})
};
})();
I am referencing the service call in customerId of resolve This is what I am passing to the ordersController.
Here is my service that is getting my customers.
(function() {
angular
.module('app.services',[])
.factory('customersFactory', customersFactory);
function customersFactory($http, $log, $q) {
return {
getCustomers: getCustomers
};
function getCustomers(){
var defer = $q.defer();
return $http.get('./Services/customers.json',{catch: true})
.then(getCustomerListComplete)
.catch(getCustomerListFailed);
function getCustomerListComplete(response) {
console.log('response.data',response.data);
// defer.resolve(response.data);
return response.data;
}
function getCustomerListFailed(error) {
console.log('error', error);
}
}
}
}());
Here is my controller. It is pretty small for right now. I am hoping to access it first. I do have customerId injected into it however.
(function() {
// 'use strict';
angular
.module('app.orders')
.controller('OrdersController', OrdersController);
function OrdersController($stateParams, customerId) {
console.log(customerId);
var vm = this;
vm.title = "Customer Orders";
vm.customer = null;
}
}());
******* Update *****
I found reviewed some code from when I was using ng-Route.
In this I used $route the same way that I am hoping to use $stateParams.
resolve: {
cityDetails:['cacFindCountry','$route', function(cacFindCountry,$route){
var countryCode = $route.current.params.countryCode;
console.log('cityDetails',cacFindCountry(countryCode))
return cacFindCountry(countryCode);
}],
countryNeighbors : ['cacFindNeighbors','$route', function(cacFindNeighbors,$route) {
var countryCode = $route.current.params.countryCode;
// pushes country code into neighbors
return cacFindNeighbors(countryCode);
}],
countryDetails : ['cacCountries', '$route', function(cacCountries, $route) {
var countryCode = $route.current.params.countryCode;
console.log(countryCode);
console.log(cacCountries(countryCode));
// need to get specific country info
// return cacCountries(countryCode);
return countryCode;
}]
}

AngularJS factory not working

I have abstracted my working code from a controller into a factory, but it doesn't seem to be working and I can't find what's wrong. I opted for a factory rather than a service because I wanted to execute some code that defined the variable before returning that variable; I want to get result.station (a part of the data returned by the API), not the full result.
This is my code:
var app = angular.module("myApp", []);
app.factory('api', ['$http',
function($http) {
var station_list = [];
$http({
method: 'GET',
url: 'http://api.irail.be/stations/?format=json&lang=nl'
})
.success(function(result) {
station_list = result.station;
});
return {
Stations: function() {
return station_list;
}
};
}
]);
app.controller("myController", ['api', '$scope',
function(api, $scope) {
$scope.station_list = api.Stations();
$scope.title = "Stations";
}
]);
and a working example.
Try this:
.success(function(result) {
angular.copy(result.station, station_list);
});
You had a small error, you were replacing the array instead of populating it. I used angular.copy instead of the assignment in your factory and it works
http://plnkr.co/edit/sqgKcFZAcClmkfdXHhrz
The problem is that you are dealing with asynchronous nature of AJAX.
I would suggest to have a delegate method in controller, which will be called when the service call is complete.
Something like the following:
app.controller("myController", ['api', '$scope',
function(api, $scope) {
api.Stations( function(station_list) {
$scope.station_list = station_list;
});
$scope.title = "Stations";
}
]);
The following is a service method excerpt:
return {
Stations: function(delegate) {
if (delegate)
delegate(station_list);
return station_list;
}
};

Load views after services in angularjs

In my angular app I have a view, a controller and a service.
The service load resources ex:service load persons and initialize value with the result.
I want to load my view after my service finish his function to load his resources.
var myApp = angular.module('myApp',[]);
myApp.controller('PersonsCtrl', ($scope, Persons) {
$scope.persons = Persons.data;
});
myApp.factory('Persons', {
data: [[function that load resources => take time]]
});
So I want to load my controller when my service finish his initialization.
Some ideas?
Assuming you have a route provider, here's a basic example. When the promise is resolved, "personData" will be injected into your controller. There's not much info about what your service does, so I had to give something very generic.
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/persons', {
controller: 'PersonsCtrl',
templateUrl: 'persons.html',
resolve: {
personData: ['Persons', function(Persons) {
return Persons.getData();
}]
}
});
}]);
myApp.controller('PersonsCtrl', ($scope, personData) {
$scope.persons = personData;
});
myApp.factory('Persons', {
getData: function() {//function that returns a promise (like from $http or $q)};
});
Maybe try using promises, example below
var myApp = angular.module('myApp',[]);
myApp.controller('PersonsCtrl', ($scope, Persons) {
$scope.persons = Persons.getData().then(function(response){
//do whatever you want with response
});
});
myApp.factory('Persons', function ($http, $q) {
return {
getData: function () {
var def = $q.defer();
$http.get('url').
success(function (response) {
def.resolve(response);
})
return def.promise();
}
}
});

Resources