Loading data for controller in Angular.js with resolve and $resource - angularjs

I'm trying to load a job by Id from the API and pass it to the controller.
.when('/jobs/edit/:id', {
templateUrl: 'partials/jobs/edit',
controller: 'JobCtrl',
resolve: function($routeParams, Job){
var jobId = $routeParams.id;
return {
job: function(){
return Job.get({ id: jobId});
}
};
}
})
Controller:
angular.module('App')
.controller('JobCtrl', function ($scope, Job, $location, $routeParams) {
$scope.newJob = data.job; //does not work
$scope.errors = {};
$scope.save = function (form) {
//...
};
});
Model:
angular.module('App')
.factory('Job', function ($resource) {
return $resource('/api/jobs/:id', {
id: '#id'
}, { //parameters default
update: {
method: 'PUT'
}
});
});
How do I get the data in the controller? My resolve block in the route is not even being executed.
Edit: this page has lots of examples of different types of resolving:
http://phillippuleo.com/articles/angularjs-timing-multiple-resource-resolves-ngroute-and-ui-router

It seems like you resolve implementation is incorrect.
You could try to change router like:
.when('/jobs/edit/:id', {
templateUrl: 'partials/jobs/edit',
controller: 'JobCtrl',
resolve: {
job: function (Job, $routeParams) {
return Job.get({id: $routeParams.id});
}
}
})
And get resoled data in controller by including Job into dependencies:
angular.module('App')
.controller('JobCtrl', function ($scope, job, $location, $routeParams) {
// job is resolved here
$scope.job = job;
$scope.newJob = {};
$scope.errors = {};
$scope.save = function (form) {
//...
};
});
UPDATED
If you want to use JobCtrl either for creating and editing, you can return null in resoled job for new-job-page. It means: There aren't any job yet, till you create one.
.when('/jobs/new', {
templateUrl: 'partials/jobs/new',
controller: 'JobCtrl',
resolve: {
job: function () {
return null;
}
}
})

Related

AngularJS: Angular UI Bootstrap, pass data from modal to controller

I have correctly setup my angular modal, now I want to pass my modal data back to my controller. I am using the below code.
First my controller calls my factory service that creates the modal popup:
$scope.mymodal = myService.openModal(data);
My service is as:
function openModal (data) {
var uData = null;
if (data) {
uData = {
userName : data.setName,
gender : data.gender
}
}
var modalInstance = $modal.open({
templateUrl: 'modal.html',
controller: 'ModalController',
backdrop: 'static',
keyboard: false,
resolve: {
data: function () {
return uData;
}
}
});
modalInstance.result.then(function () {
return;
}, function () {
});
return modalInstance;
}
See my jsfiddle here for this: http://jsfiddle.net/aman1981/z20yvbfx/17/
I want to pass name & gender that i select on my modal back to my controller, which then populates my page. Let me know what is missing here.
I updated AboutController, ModalController and myService with comments.
Main idea is return data from ModalController with close method. Fiddle
var app = angular.module('myApp', ['ui.router','ui.bootstrap']);
app.controller('IndexController', function($scope, $log) {
});
app.controller("AboutController", ['$location', '$state', '$scope', '$filter','myService', function($location, $state, $scope, $filter, myService) {
var data = "";
$scope.mymodal = myService.openModal(data);
// after modal is close, then this promise is resolve
$scope.mymodal.then(function(resp){
console.log(resp);
})
}]);
app.controller("ModalController", function($location, $state, $scope, $filter, $modalInstance) {
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
$state.go('index');
};
$scope.done = function () {
// return data on close modal instance
$modalInstance.close({genger:$scope.gender,userName:$scope.userName});
};
});
app.factory('ApiFactory', function ($http) {
var factory = {};
return factory;
});
app.factory("myService",[ "$state", "$modal", "ApiFactory",
function ($state, $modal, factory) {
var service = {
openModal: openModal
};
function openModal (data) {
var uData = null;
if (data) {
uData = {
userName : data.setName,
gender : data.gender
}
}
var modalInstance = $modal.open({
templateUrl: 'modal.html',
controller: 'ModalController',
backdrop: 'static',
keyboard: false,
resolve: {
data: function () {
return uData;
}
}
});
// on close, return resp from modal
modalInstance.result.then(function (resp) {
return resp;
}, function () {
});
// return modal instance promise
return modalInstance.result;
}
return service;
}
]);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/index');
$stateProvider
.state('index', {
url: '^/index',
templateUrl: 'index.html',
controller: "IndexController"
})
.state('about', {
url: '^/about',
templateUrl: 'about.html',
controller: "AboutController"
})
}]);

How can I call controller on ui-router resolve?

This is what my ui-router looks like:
.state('colleague', {
url: "/colleague",
templateUrl: "views/colleague.html",
resolve: {
typeEmployee: function ($q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve('manager');
}, 200);
return deferred.promise;
}
,
controller: 'colCtrl'
}
})
The issue is that I can't go to the collegue page:
<a ui-sref="colleague">colleague</a>
This is the controller code:
function colCtrl() {
debugger;
console.log('type of employee is:', typeEmployee);
if (typeEmployee === 'colleague') {
console.log('not allowed to view this');
}
if (typeEmployee === 'manager') {
console.log('allowed to view this');
}
}
app.controller('colCtrl', colCtrl);
When I grab the code from the controller and paste this directly into the router it works. What do I need to fix in the code so I can use 'controller:colCtrl' in my router?
You are using controller inside the resolve. You should move that to top level of state config object.
.state('colleague', {
url: "/colleague",
templateUrl: "views/colleague.html",
controller: 'colCtrl', // Notice its same level as resolve
resolve: {
typeEmployee: function ($q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
deferred.resolve('manager');
}, 200);
return deferred.promise;
}
}
})
Here is working plunkr with your example.
Problem is that, you need to mention the Controller as a variable, not as a string.
i.e.
controller: colCtrl
not
controller: 'colCtrl'

Angular ui-router - how to assign resolved data to state data

How do I assign resolved data into state data w/o going in the controller code?
following code fails
.state('restaurant', {
abstract: true,
url: '/:restaurantId/:restaurantName',
resolve: {
restaurant: ['RestaurantFactory', '$stateParams', '$state', function (RestaurantFactory, $stateParams, $state) {
return RestaurantFactory.query({ restaurantId: $stateParams.restaurantId });
}]
},
data: {
restaurant: resolve.restaurant // fails
},
views: {
'content#': {
templateUrl: 'app/modules/restaurant/restaurant.html',
controllerAs: 'RestCtrl',
controller: ['restaurant', 'RestaurantFactory', 'AppLib', 'Page', '$scope', '$state', function (restaurant, RestaurantFactory, AppLib, Page, $scope, $state) {
var vm = this;
// public properties
vm.AppLib = AppLib;
vm.Page = Page;
vm.restaurant = restaurant;
$state.restaurant = restaurant;
$scope.$on('Restaurant_Changed', function (event, data) { if (data.id === vm.restaurant.id) { vm.restaurant = data; $state.restaurant = data; } });
}]
}
}
})
The reason I need this functionality is that one of the child state overwrites the content# view (kind of brings entire content of its own) and as a result parent's controller is never fired if I access child states page directly. Is there a way to accomplish this as I want to use parent state URL and ability to share data down to children/grandchildren states
Any ideas?
Solution
Big thanks to Yang Li for giving me this suggestion. Here is how I solved it
resolve: {
restaurant: ['RestaurantFactory', '$stateParams', '$state', '$q', function (RestaurantFactory, $stateParams, $state, $q) {
var deferred = $q.defer();
RestaurantFactory.query({ restaurantId: $stateParams.restaurantId })
.then(function (data) {
$state.restaurant = data;
deferred.resolve($state.restaurant);
})
.then(function (data) {
deferred.reject(data);
})
return deferred.promise;
}],
},

Loading controller on demand using AngularJS and RequireJS

I'm using Angular UI-router and trying to download/load controller when the routing changes. I used resolve and category, the data.data returns the js file content as string. I'm not sure to make the controller available to angular. Please help
My module.js contains below routing code
state("privacy", {
url: "/privacy",
controllerProvider: function ($stateParams) {
return "PrivacyController";
},
resolve: {
category: ['$http', '$stateParams', function ($http, $stateParams) {
return $http.get("js/privacy.js").then(function (data) {
return data.data;
});
} ]
},
templateUrl: localPath + "templates/privacy.html"
})
The below controller exist in "js/privacy.js"
socialinviter.controller("PrivacyController", function ($scope) {
$scope.me = "Hellow world";
});
I also tried with require js but I'm getting error "http://errors.angularjs.org/1.2.16/ng/areq?p0=PrivacyController&p1=not%20aNaNunction%2C%20got%20undefined"
resolve: {
deps: function ($q, $rootScope) {
var deferred = $q.defer(),
dependencies = ["js/privacy"];
require(dependencies, function () {
$rootScope.$apply(function () {
deferred.resolve();
});
deferred.resolve()
})
return deferred.promise;
}
}
I have resolved the issue and I thought the solution would be helpful for others
Step 1: On your config, include the parameter $controllerProvider
mytestapp.config(function ($stateProvider, $controllerProvider)
Step 2: telling angular to register the downloaded controller as controller, add the below inside the config
mytestapp.config(function ($stateProvider, $controllerProvider) {
mytestapp._controller = mytestapp.controller
mytestapp.controller = function (name, constructor){
$controllerProvider.register(name, constructor);
return (this);
}
......
Step 3: Add the resolve method as below
state("privacy", {
url: "/privacy",
controller: "PrivacyController",
resolve: {
deps : function ($q, $rootScope) {
var deferred = $q.defer();
require(["js/privacy"], function (tt) {
$rootScope.$apply(function () {
deferred.resolve();
});
deferred.resolve()
});
return deferred.promise;
}
},
templateUrl: "templates/privacy.html"
})

Angularjs route resolve not populating model before loading controller

I am trying to populate my model from backend(with label and messages) before my contoller get loads. My method is working fine it connects with backend and gets the data but when I am viewing that variable in controller it is coming as undefined. My variable is "Model"
This is my route file
mainApp
.config(["$routeProvider", function ($routeProvider) {
.when(AngularRoutesFactory.AIMSAdmin.SearchBookings, {
templateUrl: aimsAdminViewBase + "Bookings/SearchBookings.html",
controller: "SearchPerioperativeBookingController",
resolve: {
"Model": function (BookingFactory) {
return BookingFactory.GetSearchModel();
}
},
requireAIMSAuthorizeUser: true
})
.otherwise({
redirectTo: AngularRoutesFactory.MainApp.BaseUrl
});
}]);
My Factory is
mainApp.factory("BookingFactory", ["$location", "MainFactory",
function ($location, MainFactory) {
bookingsFactory.GetSearchModel = function () {
bookingsFactory.MainFactory.QueryAPI(apiEndpoint + "GetSearchModel", "GET", function (response) {
bookingsFactory.SearchBookingCriteria = response;
return bookingsFactory.SearchBookingCriteria;
}, null, null, bookingsFactory.LangInfo.Message_GettingBookingModel);
}
return bookingsFactory;
}]);
And this is my controller
mainApp.controller("SearchBookingController", ["$scope", "BookingFactory", "$rootScope", "$location"
, function ($scope, BookingFactory, $rootScope, $location, Model) {
$scope.bbb = Model;
}]);
Edit:
Try handling it this way:
mainApp.config(["$routeProvider", "$q", function ($routeProvider, $q) {
.when(AngularRoutesFactory.AIMSAdmin.SearchBookings, {
templateUrl: aimsAdminViewBase + "Bookings/SearchBookings.html",
controller: "SearchPerioperativeBookingController",
resolve: {
Model: function (BookingFactory, $q) {
var deferred = $q.defer();
BookingFactory.GetSearchModel().then(
function (data) {
deferred.resolve(data);
}, function () {
deferred.reject();
}
);
return deferred.promise;
}
},
requireAIMSAuthorizeUser: true
})
.otherwise({
redirectTo: AngularRoutesFactory.MainApp.BaseUrl
});
}]);
Took guidance from #Fedaykin and came up with following working solution. Please let me know if it is wrong
I just changed my factory method and resolve function by applying $q.defer method and got it working
Changed my factory GetSearchModel method with following code
bookingsFactory.GetSearchModel = function () {
bookingsFactory.MainFactory.QueryAPI(apiEndpoint + "GetSearchModel", "GET", function (response) {
deferred.resolve(response);
}, null, null, bookingsFactory.LangInfo.Message_GettingBookingModel);
return deferred.promise;
}
What I did in route file
var bookingModel= function ($q, BookingFactory) {
var deferred = $q.defer();
BookingFactory.GetSearchModel().then(
function (data) {
deferred.resolve(data);
}, function () {
deferred.reject();
}
);
return deferred.promise;
};
bookingModel.$inject = ["$q", "BookingFactory"];
Then in resolve all I did
.when(AngularRoutesFactory.AIMSAdmin.SearchBookings, {
templateUrl: aimsAdminViewBase + "Bookings/SearchBookings.html",
controller: "SearchBookingController",
resolve: {
"Model": bookingModel
},
requireAIMSAuthorizeUser: true
})
And in controller voila I got the value
mainApp.controller("SearchBookingController", ["$scope", "InitializeMainFactory", "$rootScope", "$location", "Model"
, function ($scope, InitializeMainFactory, $rootScope, $location, Model) {
$scope.Model = Model;
}]);

Resources