I have this situation
two files, both in the same app
var app = angular.module('myapp');
file one is the parent and I have:
app.controller("ControllerOne", ['$scope', '$http', '$modal',
function ($scope, $http, $modal) {
$scope.$on('refreshList', function (event, data) {
console.log(data);
});
$scope.openModal = function () {
var modalInstance = $modal.open({
templateUrl: '/SomeFolder/FileWithControllerTwo',
controller: 'ControllerTwo',
size: 'lg',
resolve: {
someParam: function () {
return "param"
}
}
});
}
}]);
file two is the child and I have:
app.controller("ControllerTwo", ['$scope', '$http', 'someParam',
function ($scope, $http, someParam) {
$scope.SaveSomething = function () {
$http.post(url, obj)
.success(function (data) {
$scope.$emit('refreshList', [1,2,3]);
}).error(function () {
});
};
}]);
Assuming that i can open the modal and I can "SaveSomething".
What I need to do to send some data from ControllerTwo to ControllerOne?
I already checked this post Working with $scope.$emit and .$on
but I cant't solve the problem yet.
Obs:
FileOne.js -> I have the ControllerOne (parrent) -> $on
FileTwo.js -> I have the ControllerTwo (child) -> $emit
Yes, I can hit the code inside $http.post.success condition
Assuming you are using angular-ui bootstrap (which has a $model), then the $scope in the model is a childscope of $rootScope.
According to $model documentation you can supply the ControllerOne $scope by using the scope option which will make the modal's $scope a child of whatever you supply. Thus:
var modalInstance = $modal.open({
templateUrl: '/SomeFolder/FileWithControllerTwo',
controller: 'ControllerTwo',
size: 'lg',
scope: $scope,
resolve: {
someParam: function () {
return "param"
}
}
});
Then you could emit to that using $scope.$parent.$emit(...). Strictly speaking, this creates a coupling in that it assumes that the user of the modal listens to the events.
If you don't want to inject your scope, they you could inject $rootScope and emit on that. But that would also send the event to every scope in the application.
This is assuming that you actually want to leave the modal open and send a message back to the parent controller. Otherwise, just use close() or dismiss() methods.
Related
I'm trying to get modals woking with angular bootstrap. I can launch the modal just fine, but I'm having some scope issues dismissing the modal.
When I launch the modal, I can specify a controller that I can call functions from, which works, but it seems to be a copy of the controller without a $parent and without any controller-local variables.
I need access to the return value of $uibModal.open() in order to close the modal, so I'm trying to store it in var modalInstance, which works fine when I'm within the scope of the controller, but the copy of the controller passed into the $uibModal service doesn't have the local variable modalInstance set.
I can get around this by storing the return object in the $rootScope, but that seems like a bad idea. Am I wrong? What's the best way to get access to modalInstance from the click handler passed into the $uibModal service? Can I avoid using the $rootScope?
var app = angular.module('main', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope, $rootScope, $uibModal) {
var modalInstance;
$scope.launch = function() {
console.log('launch');
modalInstance = $uibModal.open({
template: '<div>Modal Content - <a ng-click="close()">Close</a></div>',
controller: 'MainCtrl',
});
// Wouldn't need to do this if I could access modalInstance in close handler
$rootScope.modalInstance = modalInstance;
}
$scope.close = function () {
console.log('close');
console.log(modalInstance);
// Works, but should I be using $rootScope like this?
//$rootScope.modalInstance.close();
// Doesn't work, modalInstance is undefined
modalInstance.close();
}
});
Angular instantiates a new instance of a controller whenever it is used, and it is the same for modal. So when you specify controller: 'MainCtrl' you're telling angular you want to instantiate one of those for your modal, which is rarely what you want.
Instead you should create a separate controller for the dialog, which can return values on closing using the $uibModalInstance service.
var app = angular.module('main', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope, $rootScope, $uibModal) {
var modalInstance;
$scope.launch = function() {
console.log('launch');
modalInstance = $uibModal.open({
template: '<div>Modal Content - <a ng-click="close()">Close</a></div>',
controller: 'DialogCtrl',
});
....
}
});
app.controller('DialogCtrl', function($scope, $uibModalInstance) {
$scope.theThingIWantToSave = [];
$scope.cancel = function () {
$uibModalInstance.close($scope.theThingIWantToSave);
};
});
I have two states in my application. In each of these states I open a modal dialogs, that has their own controllers: parentCtrl and childCtrl. I wanna return to the parent modal in select(config) function and return config value to the parent state, just into parentCtrl.
$stateProvider.state('parent', {
url: "...",
onEnter: function ($stateParams, $state, $uibModal) {
$uibModal.open({
templateUrl: '...',
controller: function ($scope, $uibModalInstance) {
...
},
controllerAs: 'parentCtrl'
});
}
});
$stateProvider.state('parent.child', {
url: "...",
onEnter: function ($stateParams, $state, $uibModal) {
$uibModal.open({
templateUrl: '...',
controller: function ($scope, $uibModalInstance) {
this.select = function (config) {
debugger;
alert("Hall:"+ config.hallName+", configuration:"+ config.name+", configId: "+ config.id);
$uibModalInstance.close({data: config});
};
},
controllerAs: 'childCtrl'
}).result.finally(function () {
debugger;
$state.go('^');
});
}
});
For bootstrap modals, the modal scope will be a child of the controller's scope and in angular scope are chained.
So if you initialize your parent controller with :
$scope.modal = {};
$scope.modal.newData = function(data){};
You should be able to do in modal controller :
$scope.modal.newData (data);
Note : the intermediary object modal is because of the limit of scope inheritance, you may have not problem with this javascript but you may have with templating so i always use interdiary objects when playing around with scope inheritance.
EDIT : didn't see it was for 2 independant modals. The best would be to use what i post and to close and open again the parent modal from parent scope data in order to refresh it.
Otherwise you can emit/listen for events in angularjs using $scope/$rootScope.$on/$emit.
For this kind of stuff, use $rootScope.$on to listen, and $rootScope.emit to send event.
The result of your child modal can pass parameters.
.result.then(function (data) {
$state.go('^', data);
});
this data is the parameter you entered in the .close() operation. You can catch those params in your state config, through adding the following on your parent state definition
params: {
data: {}
}
I have a page with the Controller_1
the Controller_1 open a modal with a different controller on a different file that we call Controller_2
and then the Controller_2 open another modal that have a different controller on a different file that we call Controller_3
so we have:
Controller_1 --Open Modal--> Controller_2 --Open Modal--> Controller_3
when i close the modal with the Controller_3, I want to pass a value to the Controller_1.
my code:
Controller_1 open a modal with the Controller_2
app.controller("Controller_1", ['$scope', '$http', '$modal',
function ($scope, $http, $modal) {
$scope.openModal_1 = function () {
var modalInstance = $modal.open({
templateUrl: '/SomeFolder/FileWithController_2',
controller: 'Controller_2',
});
}
}]);
Controller_2 open a modal with the Controller_3
app.controller("Controller_2", ['$scope', '$http', '$modalInstance', '$modal',
function ($scope, $http, $modalInstance, $modal) {
$scope.SaveSomething = function () {
$http.post(url, obj)
.success(function (data) {
var modalInstance = $modal.open({
templateUrl: '/SomeFolder/FileWithController_3',
controller: 'Controller_3',
}
});
}).error(function () {
});
};
}]);
Controller_3 save something then close and pass some data to the Controller_1
app.controller("Controller_3", ['$scope', '$http', '$modalInstance',
function ($scope, $http, $modalInstance) {
$scope.SaveSomething = function () {
$http.post(url, obj)
.success(function (data) {
... pass some code to Controller_1 and close this modal.
});
}).error(function () {
});
};
}]);
Assuming that everything is working fine and all I want to do is passing some data from Controller_3 to Controller_1.
My question is:
How I can pass the data from Controller_3 to Controller_1?
I already tried pass the $scope when I open the modal as follows:
//from Controller_1 to Controller_2
var modalInstance = $modal.open({
templateUrl: '/SomeFolder/FileWithController_2',
controller: 'Controller_2',
scope: $scope,
});
in this case it work only for the Controller_2, so any modification on $scope will affect the Controller_1 but it is not working the same way if i do the same for Controller_3
I tried $emit and $on but it do not work too because they are not parent and child like this:
<div ng-controller="ParentCtrl">
<div ng-controller="ChildCtrl"></div>
</div>
they are complete different controllers in different files.
See $parent in Angular doc
Declare your modal instance,
var modalInstance = $modal.open({
templateUrl: '/SomeFolder/FileWithController_3',
controller: 'Controller_3',
scope: $scope.$parent,
});
So you can basically call a method or edit a property from controller_1 in your controller_3.
app.controller("Controller_3", ['$scope', '$http', '$modalInstance',
function ($scope, $http, $modalInstance) {
app.controller("Controller_3", ['$scope', '$http', '$modalInstance',
function ($scope, $http, $modalInstance) {
$scope.SaveSomething = function () {
$http.post(url, obj)
.success(function (data) {
$scope.$parent.modethodToCall(data);
})
.error(function () {});
};
}]);
I think you have to add another $parent because $modal create it's own child $scope. If someone can confirm ?
I personnaly won't recommand to use parent properties/methods. In my projects i create modal instance with params and return an object on modal closure. (See $modal in Angular ui doc)
$modalInstance.close(data);
You may use events and listen to these events.
Follow bellow an example:
app.controller('controller1', ['$scope','$rootScope', controller1]);
function controller1($scope, $rootScope){
$scope.$on('informController1', informController1);
function informController1(information){
//information displayed on the controller 1 related view
$scope.ctrl1Information = information;
}
}
app.controller('controller2', ['$scope','$rootScope', controller2]);
function controller2($scope, $rootScope){
//controller2 logic
}
app.controller('controller3', ['$scope','$rootScope', controller3]);
function controller3($scope, $rootScope){
$scope.$on('informController3', informController3);
function informController3(information){
//information displayed on the controller 3 related view
$scope.ctrl3Information = information;
}
function closeModal(){
//close modal code...
$rootScope.$broadcast('informController1', $scope.ctrl3Information);
}
}
For this approach to work, you have to make sure the controller is loaded when the event was triggered.
I'm currently working on an app where a button triggers a method that will emit an event to elsewhere. This works great, however I also want to add a url to trigger this action.
So currently my button looks like this
<a class="addJob" ng-click="addNewJob()" ng-controller="AddJobController"></a>
But what I really want is it to just be
<a class="addJob" href="/new"></a>
Now, I can't figure out how to do the routing for this. It would mean that when I go to /new, the AddJobController should be triggered.
When I go directly to http://www.example.com/new, it should still load the page properly and trigger that action.
I don't want to create a separate page for this route as it is an essential part of the app flow.
(Think of it like when you create a new note in trello.com)
One Option
If you are willing to move to uiRouter, this is a common pattern.
Copied and pasted directly from the uiRouter FAQ
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-open-a-dialogmodal-at-a-certain-state
$stateProvider.state("items.add", {
url: "/add",
onEnter: ['$stateParams', '$state', '$modal', '$resource', function($stateParams, $state, $modal, $resource) {
$modal.open({
templateUrl: "items/add",
resolve: {
item: function() { new Item(123).get(); }
},
controller: ['$scope', 'item', function($scope, item) {
$scope.dismiss = function() {
$scope.$dismiss();
};
$scope.save = function() {
item.update().then(function() {
$scope.$close(true);
});
};
}]
}).result.then(function(result) {
if (result) {
return $state.transitionTo("items");
}
});
}]
})
Second Option
The second options would be to launch the modal the constructor of your controller. I have included a modalFactory. This is a common pattern. It allows your modals to be reusable, and cleans up your controllers. The uiRouter example above should use the factory pattern as well to abstract the modal setup out of the state config.
This example should work with ngRouter.
app.controller('addJobModalController', ['modalFactory', function(modalFactory) {
modalFactory.addJob();
}]);
app.factory('modalFactory', ['$modal', function($modal) {
return {
addJob: function() {
return $modal.open({
templateUrl: 'views/addjob-modal.html',
controller: 'AddJobController',
size: 'md'
});
}
}
}]);
The addJob() method returns the modal's promise. If you want, you can store this promise in the factory to be returned by another method so that another controller or service can act on the result of the modal.
I am new with Angularjs , here is my code,
angular.module('remoteApp')
.controller('ScreensavertabCtrl', function ($scope, $modal, $log, $state,Screensaverchpwservice,
Screensaverchpwgetservice) {
$scope.screensaverData = {
screensaver:{
pwProtect: '1'
}
};
$scope.pwProtectOpen = function () {
if($scope.screensaverData.screensaver.pwProtect == true){
var modalInstance = $modal.open({
templateUrl: 'pwProtectModalContent.html',
controller: pwProtectModalInstanceCtrl
});
}
};
var pwProtectModalInstanceCtrl = function ($scope, $modalInstance) {
$scope.pwProtectCancel = function () {
$modalInstance.dismiss('cancel');
console.log($scope.screensaverData.screensaver.pwProtect)
};
};});
when I enable pwProtectCancel function , I want to get $scope.screensaverData.screensaver.pwProtect
value, I tried to use '$scope.$parent.screensaverData.screensaver.pwProtect' is not work?
I am so confused about that,
anyone ideas?
Change you $modal service call to
var modalInstance = $modal.open({
templateUrl: 'pwProtectModalContent.html',
controller: pwProtectModalInstanceCtrl
scope:$scope
}
and you should get the data no the modal scope.
The documentation mentions about scope option
scope - a scope instance to be used for the modal's content (actually
the $modal service is going to create a child scope of a a provided
scope). Defaults to $rootScope
The default it gets is rootscope.