angularjs modal service broadcast and on issue - angularjs

I am using angular-modal-service library. My logic is : when the modal is open it runs a function from SomeService, and $rootScope.$broadcast from SomeService to modal controller that way I can send resource from service to my modal controller. However, it doesn't fire. Please help me to figure out what I have missed. Thank you.
**Service: **
angular.module('ng-laravel').service('SomeService', function($rootScope, Restangular, CacheFactory, $http) {
this.testFunction = function() {
console.log("from service");
$rootScope.$broadcast('event', {success:'success'});
};
}
**Controller: **
$scope.show = function(customer_id) {
ModalService.showModal({
templateUrl: 'modal.html',
inputs: {
customer_id: customer_id
},
scope: $scope,
controller: function($scope, close) {
$scope.customer_id = customer_id;
$scope.close = function(result) {
close(result, 500); // close, but give 500ms for bootstrap to animate
};
$scope.$on('event', function(event, data){
alert('yes');
console.log('from modal controller');
});
}
}).then(function(modal) {
SomeService.testFunction(customer_id, tour_id);
modal.element.modal();
modal.close.then(function(result) {
$scope.message = "You said " + result;
});
});
};
After switching the function it works, but...
how could i pass data in to modal? like ui-bs-modal, they have resolve.

You're being broadcasting event before events from modal controller are binding. So before broadcasting event make sure that event listeners are registered(meaning modal controller has been loaded). So call SomeService.testFunction(); after showModal method.
$scope.show = function(customer_id) {
ModalService.showModal({
templateUrl: 'modal.html',
inputs: {
customer_id: customer_id
},
scope: $scope,
controller: function($scope, close) {
//code as is
//listeners will get register from here.
}
})
.then(function(modal) {
SomeService.testFunction(); //broadcasting event
}).catch(function(error) {
// error contains a detailed error message.
console.log(error);
});
};

You are broadcasting the event, before the modal controller is instantiated or created, as service function is called before ModalService.showModal. Try changing the order. That should work fine.
Inside $scope.show try this order
$scope.show = function(){
ModalService.showModal({
....
// Listen for broadcast event
});
SomeService.testFunction();
}

Related

$mdDialog [$rootScope:inprog] $digest already in progress

When calling a $mdDialog and then calling one more $mdDialog right after the first one - then this error appears 3 times in a row.
No I do not use $scope.apply() or $scope.$digest() anywhere in my code.
$scope.$$phase is null at the time of the error
The full code is too big to post here, and the error happens inside the $mdDialog minified functions.
Anyway this is where we call $mdDialog:
$scope.$on('openDialog', function(event, data){
$mdDialog
// Open the dialog
.show({
template: require('./confirmDialog.html'),
parent: angular.element(document.body),
controller: function($scope) {
var vm = this;
vm.header = data.header;
vm.question = data.question;
vm.cancel = function() {
$mdDialog.cancel();
}
vm.yes = function() {
$mdDialog.hide('yes');
}
vm.no = function() {
$mdDialog.hide('no');
}
},
controllerAs: 'vm',
clickOutsideToClose:true
})
// React to answer
.then(function(modalActionResult){
console.log("scope phase", $scope.$$phase);
$scope.modalActions({'performAction': modalActionResult, 'type': data.type});
})
// Catch any errors
.catch(function(){
})
// Close and kill listeners?
.finally(function() {
});
});

Ionic/AngularJS - global modal with controller

Bear with me - I'm an AngularJS newb.
I have a form that I want to be available from anywhere in my app, and I'm trying to figure out how to code that. My current attempt is to put the modal into a service, like this:
.service('NewObjectService', function() {
var svc = this;
svc.showModal = function() {
$ionicModal.fromTemplateUrl('template.html', {
scope: null, // what should I do here?
animation: 'slide-in-up'
}).then(function(modal) {
svc.modal = modal;
modal.show();
});
}
})
.controller('NewObjectController', function() {
$scope.$on('$ionicView.enter', function() {
console.log('NewObjectController');
// setup new object
})
})
Then from anywhere in my app, I can call NewObjectService.showModal() and the modal pops up. That part is working.
The trouble I'm running into is that I can't get my controller to fire, so the initialization never gets called and my new object is null.
It seems like I should actually be calling the modal from within NewObjectController to setup scope, but I tried that and I couldn't figure out how to call that controller from within other controllers - hence the service.
I know I'm just doing something fundamentally wrong, but I'm not sure what it is. Any help?
Update: I also just tried calling one controller from another using a root scope broadcast:
.controller('MainCtrl', function() {
this.showModal = function() {
$rootScope.$broadcast('new_object:show_modal');
}
})
.controller('NewObjectCtrl', function() {
$rootScope.$on('new_object:show_modal', function() {
// show modal
})
})
The problem I'm running into there is that NewObjectCtrl hasn't been invoked at the time MainCtrl runs, so it doesn't catch the broadcast event.
When you declare a service you need to return itself in the Angular declaration ie var svc = {}; return svc; Call svc.showModal from any controller after you've injected the service and pass in the scope. Call the controller from another controller by using $rootScope.$on (receiver) and $rootScope.$emit (from)
.service('NewObjectService', function($ionicModal) {
var svc = {};
svc.showModal = function(_scope) {
$ionicModal.fromTemplateUrl('template.html', {
scope: _scope, // passing in scope from controller
animation: 'slide-in-up'
}).then(function(modal) {
svc.modal = modal;
modal.show();
});
}
return svc;
})
.controller('NewObjectController', function($scope, $rootScope, NewObjectService) {
// fires off when $rootScope.$emit('ShowModal') is called anywhere
$rootScope.$on('ShowModal', function(data) {
NewObjectService.showModal(data._scope);
});
})
.controller('OtherController', function($scope, $rootScope) {
$scope.contactOtherController = function() {
// contact the other controller from this controller
$rootScope.$emit("ShowModal", {scope: $scope});
}
})

Parent view does not get updated

I am using angular with ngDialog. I have in my view a list of users with an edit button which opens the user details in a ngDialog. Now when i save the data in my ngDialog I would like the list of users to be updated.
I thought to use a observer pattern for this. However the handler doesn't fire.
Here is my code:
User Controller
angular.module('myApp')
.controller('UserController', function($scope, User){
//this method gets fired when the dialog is saved
$scope.update = function(user)
{
User.update(user);
$scope.$broadcast('refresh-users');
return true;
}
});
UsersController:
angular.module('myApp')
.controller('UsersController', function($scope, User, ngDialog){
var loadUsers = function(users) {
$scope.users = users;
}
var handleErrors = function(response) {
console.error(response)
}
$scope.userPopup = function(id)
{
ngDialog.open(
{
template:'../partials/user.html',
controller: 'UserController',
data: {'id': id},
scope: $scope
});
}
$scope.$on('refresh-users', function handler(){
console.log('handler');
User.getAll()
.then(loadUsers)
.catch(handleErrors);
});
});
How could I solve this?
Use $rootScope instead of $scope as these two controllers are not using the same scope.
As has already been mentioned you want to use $rootScope for broadcasting if what you're trying to communicate is on another scope.
User Controller
angular.module('myApp')
.controller('UserController', function($scope, $rootScope, User){
//this method gets fired when the dialog is saved
$scope.update = function(user)
{
User.update(user);
$rootScope.$broadcast('refresh-users');
return true;
}
});
UsersController:
angular.module('myApp')
.controller('UsersController', function($scope, $rootScope, User, ngDialog){
var loadUsers = function(users) {
$scope.users = users;
}
var handleErrors = function(response) {
console.error(response)
}
$scope.userPopup = function(id)
{
ngDialog.open(
{
template:'../partials/user.html',
controller: 'UserController',
data: {'id': id},
scope: $scope
});
}
$rootScope.$on('refresh-users', function handler(){
console.log('handler');
User.getAll()
.then(loadUsers)
.catch(handleErrors);
});
});

How to close Angular UI Modal from anywhere

I am using the Angular UI bootstrap modal dialog and create it within a service:
myApp.factory('ModalService', ['$modal', function($modal) {
return {
trigger: function(template) {
$modal.open({
templateUrl: template,
size: 'lg',
controller: function($scope, $modalInstance) {
$scope.ok = function() {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
}
});
},
close: function() {
// this should close all modal instances
}
};
}]);
How can I close all modal instances when calling ModalService.close() from a controller or whatsoever?
Inject the $modalStack service and call the function $modalStack.dismissAll(), see the code on GitHub for details:
myApp.factory('ModalService', ['$modal', '$modalStack' function($modal, $modalStack) {
return {
trigger: function(template) {
$modal.open({
templateUrl: template,
size: 'lg',
controller: function($scope, $modalInstance) {
$scope.ok = function() {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
}
});
},
close: function(reason) {
$modalStack.dismissAll(reason);
}
};
}]);
I added the below line to prevent browser back button routing and closing the popup. We need to inject $modalStack into angular controller.
event.preventDefault();
$modalStack.dismissAll('close');
This is how i got it working in my project without using any factory or additional code.
//hide any open $mdDialog modals
angular.element('.modal-dialog').hide();
//hide any open bootstrap modals
angular.element('.inmodal').hide();
//hide any sweet alert modals
angular.element('.sweet-alert').hide();
I have a timeout function that emits logout as $rootScope.$emit('logout'); and the listener in my service is as follows:
$rootScope.$on('logout', function () {
//hide any open $mdDialog modals
angular.element('.modal-dialog').hide();
//hide any open bootstrap modals
angular.element('.inmodal').hide();
//hide any sweet alert modals
angular.element('.sweet-alert').hide();
//do something else here
});
I don't know if this is the right approach , but it works for me.

AngularUI Bootstrap Modal Open event

I'm invoking a bootstrap modal dialog through a link.
I want to start a timer in the angular controller when the dialog pops up. How do I detect the dialog open event in the angular controller to start the timer?
If I start timer in the scope like this,
app.controller('myctrl',
['$scope', '$window', '$timeout', 'svc',
function ($scope, $window, $timeout, svc) {
$scope.countdown = 10;
$scope.runCounter = function () {
$scope.countdown -= 1;
if ($scope.countdown > 0)
$timeout($scope.runCounter, 60000);
}
$scope.runCounter();
}]);
the timer starts when the application starts. I want the timer to start only when the dialog opens.
Thanks.
Check this out.
var modalInstance = $modal.open({...});
modalInstance.opened.then(function() {
alert("OPENED!");
});
The $modal.open() returns an object that, among other properties contains the opened promise, to be used as above.
I assume that you are using modals from http://angular-ui.github.io/bootstrap/.
If you look closely you will see that the component expose a promise that will be resolved when the dialog is opened. Which is what you will need to use. You can do something like that in the controller where the modal is created:
$scope.runCounter = function () {
$scope.countdown -= 1;
if ($scope.countdown > 0)
$timeout($scope.runCounter, 60000);
}
//Creating the dialog
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl
}
});
//Add a function for when the dialog is opened
modalInstance.opened.then(function () {
$scope.runCounter
});
See working plunker here
var modalInstance = $modal.open({
templateUrl: '../augustine_app/templates/program_purchase_popup.html',
backdrop: 'static',
controller: function ($scope, $modalInstance) {
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
});
if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
modalInstance.opened.then(function () {
var modal;
var getModalInterval = function () {
modal = document.getElementsByClassName('modal')[0];
if (modal) {
clearInterval(getModal);
modal.style.marginTop = window.screenTop + 'px';
modal.style.height = 'auto';
modal.style.position = 'absolute';
modal.style.overflow = 'visible';
}
};
modal = document.getElementsByClassName('modal')[0];
if (!modal) {
var getModal = setInterval(getModalInterval, 2000);
}
});
}
};
Unfortunatly the open.then(func) runs before the freaking modal is actually in the DOM. Hence the setInterval.
here is some non jQuery angular code.
For my case, I need to be able to detect when modal is opened inside the modal controller itself.
At first opened promise was resolved even though the modal hasn't been loaded in the DOM yet. By wrapping the call inside a $timeout, opened promise is now resolved after the modal is loaded to the DOM.
$modal.open({
templateUrl: 'modalTemplate.html',
controller: 'modalCtrl'
});
// inside modalCtrl
angular.controller('modalCtrl', ['$modalInstance', '$timeout', function($modalInstance, $timeout) {
$timeout(function() {
$modalInstance.opened.then(function() {
//do work
});
});
}]);

Resources