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"
})
}]);
Related
I tried to make modal popup with angularjs, webpack2.
But some problems are bothering me..
I want to make modal popup that has custom url but
in modal popup, $state.current still indicates parent's state.
I searched onEnter function is invoked when state transition is done completely.
and meantime, modal's state is not updated. (I think this is the reason why modal's state indicates parent's state)
I can get modal's own state and stateParams with setTimeout function but it is just trick right ?
How can I get modal's state with the right way?
===
this is my app.js,
// HOME
.state('home', {
url: '/',
templateUrl: 'client/pages/home/home.html',
controller: 'HomeController',
})
// PLAYER MODAL
.state('player', {
url: 'player/:playerName',
parent: 'home',
onEnter: function($stateParams, $state, $uibModal) {
$uibModal.open({
templateUrl: 'client/pages/player/player.html',
resolve: {},
controller: 'PlayerController'
}).result.then(function (result) {
// $scope.$close
alert('result ->' + result);
}, function (result) {
// $scope.$dismiss
alert('dismiss ->' + result);
}).finally(function () {
// handle finally
return $state.go('home');
});
}
});
HomeController,
angular.module('907degree')
.controller('HomeController', function ($scope, $state) {
$scope.state = $state.current;
$scope.players = ['messi', 'hazard', 'ronaldo'];
$scope.showModal = function (playerId) {
$state.go('player', { playerName: playerId });
};
})
and PlayerController.
angular.module('907degree')
.controller('PlayerController', ($scope, $http, $state, $stateParams, itemService) => {
$scope.playerState = $state.current;
$scope.params = $stateParams.playerName;
$scope.item = itemService.get($stateParams.id);
$scope.ok = function () {
$scope.$close('clicked OK');
};
$scope.dismiss = function () {
$scope.$dismiss('clicked CANCEL');
};
$scope.checkState = function () {
console.log($state.current, $stateParams);
console.log($scope.playerName);
}
})
I think my repo is better than plunker to solve this problem.. so here is it.
git clone hagfish1210#gitlab.com/hagfish1210/907degrees.git & npm install & npm run dev
Inject the current $transition$.
onEnter: function($transition$, $state, $uibModal) {
$uibModal.open({
templateUrl: 'client/pages/player/player.html',
resolve: { $transition$: () => $transition$ },
controller: 'PlayerController'
}).result.then(function (result) {
// $scope.$close
alert('result ->' + result);
}, function (result) {
// $scope.$dismiss
alert('dismiss ->' + result);
}).finally(function () {
// handle finally
return $state.go('home');
});
}
In PlayerController ask the transition for its parameters
angular.module('907degree')
.controller('PlayerController', ($scope, $http, $state, $transition$, itemService) => {
$scope.playerState = $state.current;
var params = $transition$.params();
$scope.params = params.playerName;
$scope.item = itemService.get(params.id);
$scope.ok = function () {
$scope.$close('clicked OK');
};
$scope.dismiss = function () {
$scope.$dismiss('clicked CANCEL');
};
$scope.checkState = function () {
console.log($state.current, params);
console.log($scope.playerName);
}
})
The Transition class exposes much information about the running transition: https://ui-router.github.io/ng1/docs/latest/classes/transition.transition-1.html#params
I'm using angular-ui-bootstrap in my project and working with bootstrap modal. But I'm having a problem with my modal when I submit I can't call to scope and I got a error "$scope.testAlert is not a function"
controller:
$scope.open = function () {
$uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'userModal.html',
controller: function ($scope, $uibModalInstance, user) {
$scope.user = user;
$scope.save = function () {
var editUser = userService.updateUser($scope.user);
editUser.then(function () {
getAllUsers();
$scope.testAlert();
})
$uibModalInstance.close();
}
},
resolve: {
user: function () {
return $scope.user;
}
}
});
}
$scope.testAlert = function () {
alert("Blah blah");
}
$scope.testAlert is on the $scope of the main controller rather than the modal controller. You need to move it like this:
$scope.open = function() {
$uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'userModal.html',
controller: function($scope, $uibModalInstance, user) {
$scope.user = user;
$scope.save = function() {
var editUser = userService.updateUser($scope.user);
editUser.then(function() {
getAllUsers();
$scope.testAlert();
})
$uibModalInstance.close();
$scope.testAlert = function() {
alert("Blah blah");
}
}
},
resolve: {
user: function() {
return $scope.user;
}
}
});
}
My restful controller is receiving a null Request Body from an angular POST and I'm not sure why.
Here's the code for my controller:
adminController.controller('ModalCtrl', ['$scope', '$modal', '$log', 'Profile', 'AvailableProfiles',
function ($scope, $modal, $log, Profile, AvailableProfiles) {
$scope.open = function (uuid, profile) {
var modalInstance = $modal.open({
animation: true,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
profile: function () {
return profile;
},
AvailableProfiles: function () {
return AvailableProfiles;
}
}
});
modalInstance.result.then(function () {
Profile.save({uuid: uuid}, {profile: profile});
}, function () {});
};
}]);
And here's the code for my service:
adminService.factory('Profile', ['$resource',
function($resource, uuid, profile) {
return $resource(baseUrl + 'candidate/:uuid/profile', {profile}, {
save: {method: 'POST', params: {uuid: uuid}},
});
}
]);
Any thoughts on why this profile object isn't being passed into the post?
Call save on the profile object.
modalInstance.result.then(function () {
profile.$save({uuid: uuid});
}, function () {});
I am trying to follow this example to show a bootstrap modal on a certain state. It works fine without a modal (so the state config should be ok). All needed dependencies (ie angular bootstrap) should be available.
when I do a console.debug($stateParams) before $modal.open I get the correct data, within the $modal.open-method however the stateParams from the last state are returned (the state I am coming from)
Any hints?
EDIT
the relevant state cfg:
.state('publications.view', {
parent: 'publications.productSelection',
url: '/{productSlug:[a-zA-Z0-9-]+}/{docID:[0-9]+}_{slug:[a-zA-Z0-9-]+}',
onEnter: ['restFactory', '$state', '$stateParams', '$modal',
function(restFactory, $state, $stateParams, $modal) {
console.debug($stateParams.docID);
$modal.open({
templateUrl: 'partials/publication.html',
resolve: {
publication: ['restFactory', '$stateParams',
function(restFactory, $stateParams) {
console.debug($state.params);
console.debug($stateParams);
return restFactory.view($stateParams.language, $stateParams.productSlug, $stateParams.docID);
}
]
},
controller: ['$scope', '$sce', 'publication', '$rootScope',
function($scope, $sce, publication, $rootScope) {
$rootScope.pageTitle = publication.data.data.publication.Publication.title;
$scope.publication = $sce.trustAsHtml(publication.data.data.publication.Publication.content);
}
]
});
}
]
});
You can get around this issue by injecting the current $stateParams into the onEnter function, save them as state in some service, and inject that service instead into your modal resolves.
I am adapting the code from here: Using ui-router with Bootstrap-ui modal
.provider('modalState', function($stateProvider) {
var modalState = {
stateParams: {},
};
this.$get = function() {
return modalState;
};
this.state = function(stateName, options) {
var modalInstance;
$stateProvider.state(stateName, {
url: options.url,
onEnter: function($modal, $state, $stateParams) {
modalState.stateParams = $stateParams;
modalInstance = $modal.open(options);
modalInstance.result['finally'](function() {
modalInstance = null;
if ($state.$current.name === stateName) {
$state.go('^');
}
});
},
onExit: function() {
if (modalInstance) {
modalInstance.close();
}
}
});
};
})
Then in your app config section
.config(function($stateProvider, $urlRouterProvider, modalStateProvider) {
modalStateProvider.state('parent.child', {
url: '/{id:[0-9]+}',
templateUrl: 'views/child.html',
controller: 'ChildCtrl',
resolve: {
role: function(Resource, modalState) {
return Resource.get({id: modalState.stateParams.id}).$promise.then(function(data) {
return data;
});
}
}
});
}
seems like $stateParams is not working.
passing date like this:
$state.go('state2', { someParam : 'broken magic' });
params being ignored on the target state
console.log('state2 params:', $stateParams); // return empty object {}
code:
var app = angular.module('app', [
'ui.router'
]);
app.config(function($stateProvider) {
$stateProvider
.state('state1', {
url: '',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $stateParams) {
$scope.go = function () {
$state.go('state2', { someParam : 'broken magic' });
};
console.log('state1 params:', $stateParams);
}
})
.state('state2', {
url: 'state2',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $stateParams) {
$scope.go = function () {
$state.go('state1', { someOtherParam : 'lazy lizard' });
};
console.log('state2 params:', $stateParams);
}
});
});
Live example can be found here
thank you.
You can't pass arbitrary parameters between states, you need to have them defined as part of your $stateProvider definition. E.g.
$stateProvider
.state('contacts.detail', {
url: "/contacts/:contactId",
templateUrl: 'contacts.detail.html',
controller: function ($stateParams) {
console.log($stateParams);
}
}) ...
The above will output an object with the contactId property defined. If you go to /contacts/42, your $stateParams will be {contactId: 42}.
See the documentation for UI-Router URL Routing for more information.
if you don't want to define your parameter in the url, you must include a params property on the state you are transitioning to. Otherwise the data will be removed from the $stateParams object. The format of the params object is an array of strings in older versions of angular-ui-router; in newer versions it is an object of empty objects:
params: { id: {}, blue: {}}
See this example:
$stateProvider.state('state1', {
url: '',
params: {
id: 0,
blue: ''
},
templateUrl: 'state-1.html',
controller: function($scope, $state, $stateParams) {
$scope.go = function() {
$state.go('state2', {
id: 5,
blue: '#0000FF'
});
};
console.log('state params:', $stateParams);
}
});
Related question:
Parameters for states without URLs in ui-router for AngularJS
Just passing parameters to a state is not enough. You have to define the parameter explicitly by name in the url property of your state.
If you don't do this, ui-router won't know this state is expecting a parameter and the $stateParams object will not be populated like you want.
Here is an example of how you might modify your state to expect a parameter, inject $stateParams, and do something with said parameter:
$stateProvider.state('state1', {
url: '',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state2', { id : 'broken magic' });
};
console.log('state1 params:', $stateParams);
}
})
.state('state2', {
url: 'state2/:id',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state1', { someOtherParam : 'lazy lizard' });
};
console.log('state2 params:', $stateParams);
}
})
Here is a working example of passing state params on jsfiddle.
the solutions above works but for my case I needed to pass query parameter so I dit it like this:
$stateProvider
.state('state1', {
url: '/state1?other',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state2', { someParam : 'broken magic' });
};
console.log('state1 params:', $stateParams);
}
})
.state('state2', {
url: '/state2?someParam',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $stateParams) {
$scope.params = $stateParams;
$scope.go = function () {
$state.go('state1', { other : 'lazy lizard' });
};
console.log('state2 params:', $stateParams);
}
});
Make a transport and use it!
angular_app.factory('$$transport', function($q) {
var transport;
return transport = {
dfr: $q.defer(),
push: function(v) {
return transport.dfr.resolve(v);
},
then: function(s, f) {
if (f == null) {
f = function() {};
}
return transport.dfr.promise.then(function(_s) {
s(_s);
transport.dfr = $q.defer();
return transport.then(s, f);
}, function(_f) {
f(_f);
transport.dfr = $q.defer();
return transport.then(s, f);
});
}
};
});
$stateProvider.state('state1', {
url: '/state1?other',
templateUrl: 'state-1.html',
controller : function ($scope, $state, $$transport) {
$$transport.then(function(s) {
$scope.param = s
console.log('state1 params:', s);
});
$scope.go = function () {
$state.go('state2', { someParam : 'broken magic' });
}
}
})
.state('state2', {
url: '/state2?someParam',
templateUrl: 'state-2.html',
controller : function ($scope, $state, $$transport) {
$scope.go = function () {
$$transport.push({other:'lazy lizard'});
$state.go('state1');
};
}
});