Angular UI-Router - using "resolve" directly on template url - javascript

I am using UI-Router and want to change routing to be 'component based'. So Instead of defining a controller / template I want to use it like this:
.state('issue', {
url: '/someUrl/:number',
template: '<my-directive></my-directive>',
resolve: {
data: function(dataService) {
return dataService.getData().then(function(response) {
console.log(response.data);
return response.data;
});
}
}
})
Now, I know that with Angular's ngRoute I can use resolved data directly in the template, for example:
$routeProvider
.when('/', {
template: `<my-directive data="resolve.data"></my-directive>`,
resolve: {
data: function (dataService) {
return dataService.getData();
}
}
})
I couldn't do it using UI-Router (value was undefined).
Am I doing something wrong? Is it possible using ui-router?

The point with UI-Router is - result of resolve is available for a controller (related to template). So, we could do it like this:
.state('issue', {
url: '/someUrl/:number',
template: '<my-directive data="stateCtrlData"></my-directive>',
controller: function($scope, data) { $scope.stateCtrlData = data },
resolve: {
data: function(dataService) {
return dataService.getData().then(function(response) {
console.log(response.data);
return response.data;
});
}
}
})
The data are passed into controller and from its scope we pass it to directive.

If you mean injecting your data service, then you can do it like this (remember that the '' is telling to inject):
state('issue', {
url: '/someUrl/',
template: '<my-directive data="pep.data"></my-directive>',
controller: function( data) { this.data = data },
controllerAs: 'pep',
resolve:{
dataSvc : 'YourDataSvc',
campaign : function(dataSvc){
return dataSvc.getData();
}
}
Please remember a ui-view will be expected if you want to put additional views or child states.

Actually you can (tested only in ui-router v0.3.2)
There's an undocumented $resolve variable which is automatically injected in the controller.
Simply add 'controllerAs' property to the state as follows, and you can use $resolve in the template:
.state('issue', {
url: '/someUrl/:number',
template: '<my-directive data="vm.$resolve.data"></my-directive>',
controllerAs: 'vm',
resolve: {
data: function(dataService) {
return dataService.getData().then(function(response) {
console.log(response.data);
return response.data;
});
}
}
})

Related

AngularJS not routing properly

I am learning Angular, so here is my testapp : http://enrolin.in/test/#/students
Now here I want to search the database by name. So I created the php that returns exactly what I need. Here is the php : http://enrolin.in/test/login.php?p=fetchbyname&&name=ak You have to replace name in the url to anything you need to search. I also created a partial page that returns absolutely correct results, here is the page: http://enrolin.in/test/#/studentSearch/ak Everything was fine till now But here is the problem:
When I try to search in http://enrolin.in/test/#/students , angularJS does not route me to something like http://enrolin.in/test/#/studentSearch/ak but instead to the default that I have set in $routeProvider
Here is my angularJS (I have removed some unimportant code):
The route provider:
.config(function ($routeProvider) {
$routeProvider
.when("/students/:id", {
templateUrl: "templates/studentDetails.html",
controller: "studentDetailsController"
})
.when("/studentSearch/:name", {
templateUrl: "templates/studentSearch.html",
controller: "studentSearchController"
})
.otherwise({
redirectTo: "/home"
})
})
The Controller that passes the link:
.controller("studentsController", function ($scope, $http, $route,$location) {
$scope.searchStudent=function(){
if($scope.name){
$location.url("/studentsSearch/" + $scope.name);
}
else{
$location.url("/studentsSearch/");
}
}
$scope.reloadData=function(){
$route.reload();
}
$http.get("http://enrolin.in/test/login.php?p=fetchall")
.then(function (response) {
$scope.students = response.data;
})
})
The controller that fetches data and displays:
.controller("studentSearchController", function ($scope, $http, $routeParams) {
if($routeParams.name)
{
$http({
url: "http://enrolin.in/test/login.php?p=fetchbyname&&name=",
method: "get",
params: { name: $routeParams.name }
}).then(function (response) {
$scope.studs = response.data;
})
}
else
{
$http.get("http://enrolin.in/test/login.php?p=fetchall")
.then(function (response) {
$scope.students = response.data;
})
}
})
Previously everytime I wanted to put a link in html to route I used to write like courses But now when I want to put it in the function instead, I am not sure what to write. Please Help.
Hi #AkhilEshKhajuria,
You are not using the same name what you have mentioned in the routing config. Routing name is "/studentSearch/:name?" but you have used in the function as "/studentsSearch/".
Please try replacing $location.url("/studentsSearch/" + $scope.name); with $location.path("/studentsSearch/" + $scope.name);
Correct the naming issue and it should work.
I tried this and it works fine.

How do I poll a database and populate a controller using AngularJs, Ui-Router, and MongoDB?

I've been trying to get my Angular app to populate the controller with data from a database (mongodb) before the page loads. I can't quite get it to work. I'm trying to use the "resolve" property of angular ui-router but it's not working and I can't figure it out!!
Here's the full code for my app:
var freezerApp = angular.module('freezerApp', ['ui.router']);
freezerApp.config([
'$stateProvider','$urlRouterProvider',function($stateProvider,$urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: '/partials/home.html',
controller: 'freezerCtrl',
});
$stateProvider
.state('freezer', {
url: '/freezers',
templateUrl: 'partials/freezers.html',
controller: 'freezerCtrl',
//not working:
resolve: {
freezerPromise: function($scope){
return $scope.getAll();
}
};
});
$urlRouterProvider.otherwise('home');
}]);
freezerApp.controller('freezerCtrl', ['$scope', '$http', function ($scope,$http) {
$scope.freezer =
{'freezername':'Freezer Name',
'building':'Building',
'floor':'Floor',
'room':'Room',
'shelves': 0,
'racks': 0
};
$scope.add_freezer = function() {
$scope.freezers.push(
{'freezername': $scope.freezer.freezername,
'building':$scope.freezer.building,
'floor':$scope.freezer.floor,
'room':$scope.freezer.room,
'shelves': $scope.freezer.shelves,
'racks': $scope.freezer.racks
}
);
};
$scope.freezers = [
{
}
];
$scope.default_freezer = $scope.freezers[0];
$scope.getAll = function() {
return $http.get('/freezers').success(function(data){
angular.copy(data, $scope.freezers);
});
};
}]);
According to the Ui-Router Resolve Documentation:
You can use resolve to provide your controller with content or data that is custom to the state. resolve is an optional map of dependencies which should be injected into the controller.
If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the $stateChangeSuccess event is fired.
It looks like you are trying to provide $scope object from your freezerCtrl to your resolve property. This is incorrect.
I would recommend you create a factory like so for your api call.
angular.module.('freezerApp').factory('freezerFact',function($http){
return {
getAll: $http.get('/freezers')
}
});
Then inside of your freezer $state deceleration you could do it like this:
$stateProvider
.state('freezer', {
url: '/freezers',
templateUrl: 'partials/freezers.html',
controller: 'freezerCtrl',
resolve: {
freezerPromise: function(freezerFact){
return freezerFact.getAll;
}
};
});
Then you would pass the freezerPromise object into your freezerCtrl and manipulate the promise after that.

How to resolve data into nested view multiple times, with different data

I am using the AngularJS framework (as well as its ui-router), and I am having a hard time getting my data to resolve the way I want. I will give an example below of what I am trying to do:
$stateProvider
.state('home',{
views: {
'test': {
templateUrl: 'test.html',
resolve: {
config: function() {
var result = /*service call that returns json*/
return result;
}
}
controller: function($scope, config){
console.log(config);
}
},
'test': {
templateUrl: 'test.html',
resolve: {
config: function() {
var result = /*service call that returns DIFFERENT json*/
return result;
}
}
controller: function($scope, config){
console.log(config);
}
}
}
})
<div ui-view="test">
<div ui-view="test">
Is there any way in which to uniqely assign and inject 'config' into the controller so that it contains the json that its respective service call returned? The idea here is I want the same template but with different configs coming into them (scoped to that particular view). Right now, config just contains the last resolve that was executed.
I hope I am not confusing. Let me know if you need any clarifications...Much appreciated!
The views need to be named differently and so do the resolves. Using the same template for both of them is not an issue. Lastly, the resolve has to be relative to the state, not the views.
$stateProvider
.state('home',{
views: {
'test': {
templateUrl: 'test.html',
controller: function($scope, config){
console.log(config);
}
},
'test2': {
templateUrl: 'test.html',
controller: function($scope, config2){
console.log(config2);
}
}
},
resolve: {
config: function() {
var result = /*service call that returns json*/
return result;
},
config2: function() {
var result = /*service call that returns DIFFERENT json*/
return result;
}
}
})
<div ui-view="test">
<div ui-view="test2">

How to access and update resolve data of parent state inside onEnter method of child state of a ui router

So I have a ui-router state that looks like so:
Parent state
$stateProvider
.state('profile',{
url: '/profile',
views: {
'contentFullRow': {
templateUrl: 'ng/templates/profile/partials/profile-heading-one.html',
controller: function($scope, profile,misc){
$scope.profile = profile;
$scope.misc = misc;
}
},
'contentLeft': {
templateUrl: 'ng/templates/profile/partials/profile-body-one.html',
controller: function($scope, profile,misc){
$scope.profile = profile;
$scope.misc = misc;
}
},
'sidebarRight': {
templateUrl: 'ng/templates/profile/partials/todo-list-one.html',
controller: function($scope, profile,misc){
$scope.profile = profile;
$scope.misc = misc;
}
}
},
resolve: {
profile: function($http){
return $http({method: 'GET', url: '/profile'})
.then (function (response) {
console.log(response.data)
return response.data;
});
},
misc: function($http){
return $http({method: 'GET', url: '/json/misc'})
.then (function (response) {
console.log(response.data)
return response.data;
});
}
}
})
Child states
.state('profile.social', {
url: '/social',
controller:function($scope, profile, misc){
$scope.profile = profile;
$scope.misc = misc;
},
template: '<div ui-view></div>'
})
.state('profile.social.create',{
url: '/create',
onEnter: function($state){
//Will call a modal here...
//How do I access or update `$scope.profile`
//so far am doing this and it works
$state.$current.locals.globals.profile.first_name = 'My New name';
//Is there any better way of doing this?
}
})
Question
Since $scope is not available in onEnter method, how do I access or update $scope.profile
So far am doing something like:
onEnter: function($state){
$state.$current.locals.globals.profile.first_name = 'My New name';
}
This works but am wondering if there is a better way of doing this?
The correct thing to do is not try and access the controllers $scope from outside the controller. You should instead move your profile data to a service, and inject it into both the controller and the onEnter function (as needed). By separating profile data into a service, you can now access it from anywhere else too :)
For example:
.service('ProfileService', function(){
var state = {};
this.loadProfile = function(){
return $http({method: 'GET', url: '/profile'})
.then (function (response) {
console.log(response.data);
state.profile = response.data;
return state.profile;
});
};
this.getState = function(){
return state;
};
});
// the controller
controller: function($scope, ProfileService){
$scope.state = ProfileService.getState();
}
// on enter
onEnter: function($state, ProfileService){
var state = ProfileService.getState();
state.profile.first_name = 'New Name';
}
I wrapped the profile data in a container (state), so that the profile key itself can be changed. So inside your view you will need to reference your profile like so: state.profile.first_name.
Also inside your resolve you will also need to inject the service, and run the load function returning the associated promise (so that resolve actually works).
Without knowing your requirements it is hard to describe the best way to do this, but in summary, you should pull your profile data into its own service, and inject it whenever you need it. The service should also encapsulate any promises that resolve once the service data has loaded.

Putting a "resolve" on an angular-ui-router view isn't working - the page simply doesn't render

$stateProvider
.state('root', {
url: '',
views: {
'root.base': { templateUrl: '/templates/root/root.html' },
'root.sidebar': {
templateUrl: '/templates/root/root-sidebar.html',
controller: 'SomeDataController',
resolve: {
someData: function(DataService) { // DataService is an angular service for data retrieval
return DataService.getDataList(); // returns an array
}
},
}
}
});
If I attempt to run a resolve on a subview with angular-ui-router, the page simply comes up blank. If I omit the resolve, it loads fine -- but I need to resolve for some data before my controller is instantiated. Do I have my syntax correct? I've searched for examples high and low but can't seem to find any that match my situation.
Given my above example, shouldn't the "root-sidebar.html" have the scope of "SomeDataController", and shouldn't SomeDataController have the data resolved in the route definition declared above?
Your concept is working, maybe just some small settings are broken... I created working plunker
Here is the controller consuming someData
.controller('SomeDataController', function($scope, someData) {
$scope.data = someData
})
And here is our service loading some JSON and returning that as async:
.factory('DataService', ['$http',
function($http) {
return {
getDataList: function() {
return $http
.get("data.json")
.then(function(response) {
return response.data;
});
},
};
}
]);
The state defintion is unchanged (just adjusted to display the data):
$stateProvider
.state('root', {
url: '',
views: {
'root.base': {
template: '<div>root base view</div>',
},
'root.sidebar': {
template: '<div>root sidebar view' +
'<h5>the resolve data</h5>' +
'<pre>{{data | json}}</pre>' +
'</div>',
controller: 'SomeDataController',
resolve: {
someData: function(DataService) { // DataService is an angular service for data retrieval
return DataService.getDataList(); // returns an array
}
},
}
}
});
You can test that all here

Categories

Resources