Ionic - Cannot use $ionicModal inside a function - angularjs

I am trying to use $ionicModal after an asynchronous operation. What I did is placing the following code inside a callback function that executes after an associated service performs an $http call:
$ionicModal.fromTemplateUrl('templates/modals/profile-update.html', {
scope: $scope
})
.then(instance => {
vm.modal = instance;
})
The above code works fine when it's placed inside the controller's main block. However, in this case, I want it inside a function openProfilePopup. I've tried the following code but it isn't working, the modal doesn't appear and no errors are displayed in the console:
activate();
function activate() {
profPopupService
.get()
.then(openProfilePopup, handleError);
}
function openProfilePopup(profile) {
vm.profile = profile;
$ionicModal.fromTemplateUrl('templates/modals/profile-update.html', {
scope: $scope
})
.then(instance => {
vm.modal = instance;
})
.catch(error => {
$log.log(error);
});
vm.modal.show();
}
Here is the template code for the modal. I've used a separate controller for the modal instead of the controller associated with the code above.
<ion-modal-view cache-view="false">
<ion-header-bar class="bar bar-header bar-dark">
<div class="buttons">
<button class="button-icon light ion-ios-arrow-back" ng-click="dashboard.modal.hide()"></button>
</div>
<h1 id="page-title" class="title">Update Your Profile</h1>
</ion-header-bar>
<ion-content class="profile-popup" ng-controller="ProfilePopupCtrl as pp">
<form name="profileForm" method="POST" ng-submit="pp.update(profileForm.$valid)" novalidate>
<!-- Not displaying here -->
</form>
</ion-content>
</ion-modal-view>
My goal is to obtain data from the controller that initiate the modal via show() function and pass that data to the modal's controller:
function ProfilePopupCtrl($log, $scope) {
const vm = this;
vm.user = $scope.$parent.dashboard.profile;
.......
}

Call show method inside .then()
function openProfilePopup(profile) {
vm.profile = profile;
$ionicModal.fromTemplateUrl('templates/modals/profile-update.html', {
scope: $scope
})
.then(instance => {
vm.modal = instance;
vm.modal.show();
})
.catch(error => {
$log.log(error);
});
}
Or
Define the modal outside the function. Just call show method of the modal when function call is done.
.controller('MyController', function($scope, $ionicModal) {
$ionicModal.fromTemplateUrl('my-modal.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
});
$scope.openModal = function() {
$scope.modal.show();
};
$scope.closeModal = function() {
$scope.modal.hide();
};
Now in the function
function openProfilePopup(profile) {
$scope.profile = profile;
$scope.openModal();
}
You can use controller as syntax if you want to use it like, vm.something

Related

Unable to call the controller in the angular ui bootstrap $modal

I want to generate a modal pop up on click of a button. I am using ui bootstrap of angular with $modal service.
Now, when I click on button, I am writing the following code.
$scope.modalOpen = function () {
var modalInstance = $modal.open({
templateUrl: 'views/includes/someModal.html',
controller : //here I want to use the same controller where the current function is getting called
});
};
I am unable to call the same controller. Am I making any mistake? I tried Google but no success :( Please suggest. Thanks in advance :)
I am assuming the whole reason you want to do this is so you can share data (state) between the modal and the current controller.
You can achieve this without having to share the controller, using the resolve field on the modal configuration.
function CurrentController($scope, $modal) {
$scope.list = [];
$scope.modalOpen = function () {
var modalInstance = $modal.open({
templateUrl: 'views/includes/someModal.html',
controller : 'SomeOtherController',
resolve: {
list: function() { return $scope.list; }
}
});
};
}
This means that list will be dependency injected into SomeOtherController.
function SomeOtherController($scope, list) {
$scope.list = list;
}
resolve (Type: Object) - Members that will be resolved and passed
to the controller as locals; it is equivalent of the resolve
property in the router.
See the docs for $modal in angular-ui bootstrap.
If you open your modal from your controller, you can attempt something like this :
var myCtrl = this;
$scope.modalOpen = function () {
var modalInstance = $modal.open({
templateUrl: 'views/includes/someModal.html',
controller : myCtrl
});
};
But I don't think it's a good practice to reuse a controller instance.
You probably don't want to make it use the same controller. Since the scope isn't isolated, your modal can call functions from your current controller. You can also have an inline controller like the following:
The reason why you couldn't use functions from your current scope is you would have to give the modal your current scope to do that. Be careful when you do this. Your modal can mess up your current object. I went ahead and created a "save" and "cancel" button so that you can undo the changes.
Html
<div ng-controller="simpleController">
{{ item.title }}
<button ng-click="open();">Click Me</button>
</div>
modal template
<script type="text/ng-template" id="views/includes/someModal.html">
<div class="modal-header">
<h3 class="modal-title">Title!</h3>
</div>
<div class="modal-body">
title: {{ item.title }}<br/>
Click the buttons below to change the title throught the controller's function
<button ng-click="fn('test');">test</button>
<button ng-click="fn('test 1');">test 1</button>
<button ng-click="fn('test 2');">test 2</button>
</div>
<div class="modal-footer">
<button ng-click="close(true);">Save</button>
<button ng-click="close();">Close</button>
</div>
</script>
javascript
angular.module("myApp", ['ui.bootstrap']).controller("simpleController", ["$scope", "$uibModal", function($scope, $uibModal){
$scope.item = { title: "test", stuff: "other stuff"};
$scope.fn = function(title){
$scope.item.title = title;
};
$scope.open = function () {
var intialItem = angular.copy($scope.item);
var modalInstance = $uibModal.open({
templateUrl: 'views/includes/someModal.html',
controller: ["$scope", function(scope){//add other functionality here
scope.close = function(save){
if(!save){
$scope.item = intialItem;
}
modalInstance.close();
}
}],
scope: $scope
}).result.then(function(){
}, function(){
$scope.item = intialItem;//modal was dismissed
});
};
}]);

ui-bootstrap: accessing modal instance from within directive controller

Noob alert!
The question here is exactly the one that I have: angularjs - Accessing ui-bootstrap modal dismiss and close function from another controller
However, I don't understand the answer that was chosen as correct! I understand the words but don't understand how to share the controller.
I have an app controller that opens a modal, and within the modal's template, I have a directive. I would like to be able manipulate the modal instance from within the directive's controller.
Here's my markup:
<script type="text/ng-template" id="settingsModal">
<div class="modal-header">
<h3 class="modal-title">Confirm update!</h3>
</div>
<div class="modal-body">
<calendar-settings cid="calendarId"/>
</div>
<div class="modal-footer">
<!-- I want these buttons inside the directive instead -->
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
In the body of the modal, I am calling the calendarSettings directive, and I'd like to be able to use the .dismiss and .close methods of the modal instance from within my directive.
Here's what the open method looks like:
var modalInstance = $modal.open({
templateUrl: 'settingsModal',
controller: 'ModalInstanceController',
resolve: {
item: function() {
return $scope.sEntry;
},
cid: function() {
return id;
}
},
reject: {
item: function() {
return $scope.sEntry;
},
cid: function() { return null; }
}
});
And here's the ModalInstanceController:
calendarsApp.controller('ModalInstanceController', function($scope, $modalInstance, item, cid){
$scope.item = item;
$scope.calendarId = cid;
console.log(item);
$scope.ok = function () {
$modalInstance.close($scope.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
I think what I want to do is easy, but I'm not sure how to expose the modal instance controller to the directive, or if there is a different approach I should be thinking about.
NOTE: I didn't paste the code from the directive in here. But I'm trying to access the close and dismiss methods of the modal instance from within my directive's controller.
Thanks for any help!
So
var modalInstance = $modal.open({
templateUrl: 'settingsModal',
controller: 'ModalInstanceController',
resolve: {
item: function() {
return $scope.sEntry;
},
cid: function() {
return id;
}
},
reject: {
item: function() {
return $scope.sEntry;
},
cid: function() { return null; }
}
//This comes from ModalInstanceController result is
//equivalent to whatever u send back
}).result.then(function(result){
console.log(result); //Press f12 on chrome and go to console.
});
calendarsApp.controller('ModalInstanceController', function($scope, $modalInstance, item, cid){
$scope.item = item;
$scope.calendarId = cid;
console.log(item);
$scope.ok = function () {
//You are sending back $scope.item but if you want everything
//send back the $scope which is equivalent to sending back //ModalInstanceController
// $modalInstance.close($scope.item);
$modalInstance.close($scope);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});

How to make Modal Service in IONIC?

I am sorry. I am starter on IONIC, i am going to use a modal service in a app. so i can only change the template url...? the modal is shown, but i can't close the modal by the closeModal() function.
Here is my factory.
.factory('ModalSvc',function($ionicModal, $rootScope){
return {
setModalView : function( url ) {
$ionicModal.fromTemplateUrl(url, {
scope: $rootScope
}).then(function(modal) {
$rootScope.modal = modal;
});
},
openModal : function() {
$rootScope.modal.show();
},
closeModal : function() {
$rootScope.modal.hide();
}
}
});
In a controller:
ModalSvc.setModalView('templates/popup-search-order.html');
$rootScope.openModel = function () {
ModalSvc.openModal();
};
$rootScope.hideModel = function () {
ModalSvc.closeModal();
};
What's wrong? and what i have to for close the modal view...
This is possible problem. That is, i can use a modal dialog service instead of some modal view...?
Thank you in advance.
Kind Regards
I do this a lot with apps I am working on now. There are a few general angular concepts you will need to understand in depth; 1 is Promises using $q and the other is all the gotchas around scopes and using $rootScope. I will let you do that research on your own or learn as you get your fingers burned now and again while using it (muhahahahaha) See code below.
.factory('ModalSvc',function($ionicModal, $rootScope, $q){
return {
setModalView : setModalView
}
function setModalView(url) {
var def = $q.defer();
var modalScope = $rootScope.$new();
modalScope.cancelModal = cancelModal;
$ionicModal.fromTemplateUrl(url, {
scope: modalScope
}).then(function(modal) {
modalScope.modal = modal;
modalScope.modal.show();
});
function cancelModal() {
modalScope.modal.hide();
modalScope.modal.remove();
// you can resolve the result of the modal here
def.resolve();
}
return def.promise;
}
});
You html could then look like this
<ion-modal-view>
<ion-header-bar class="bar-positive">
<button class="button button-clear button-icon icon ion-close-round" ng-click="cancelModal()"></button>
<h1 class="title">Modal Title</h1>
</ion-header-bar>
<ion-content has-header="true">
</ion-content>
</ion-modal-view>

UI Bootstrap Modal within Directive

I'm using Angular 1.4.1 and UI Bootstrap 0.13.
I have a directive from which I'm opening a modal. The modal opens fine, but the buttons seemingly don't get bound to their handlers - they don't do anything. I've used this same code in another project just fine, except not from within a directive.
My directive:
(function () {
var app = angular.module('myApp');
app.directive('someDirective', function () {
return {
restrict: 'E',
templateUrl: 'SomeDirective.html',
scope: {
list1: '=list1',
list2: '=list2',
save: '&'
},
controller: ['$scope','$modal','myService', function ($scope,$modal,myService) {
$scope.openModal = function () {
var modalInstance = $modal.open({
templateUrl: 'ModalTemplate.html',
controller: 'modalController',
backdrop: 'static',
size: 'sm',
resolve: {
saveData: function () {
//do save action
}
}
});
modalInstance.result.then(
function (itemToSave) {
//save item
},
function () {
//Cancel
}
);
};
}]
}
});
}());
The modal's controller:
(function() {
var app = angular.module('myApp');
app.controller('modalController', [
'$scope', '$modalInstance', 'saveData',
function($scope, $modalInstance, saveData) {
$scope.saveData = saveData;
$scope.save = function() {
$modalInstance.close($scope.saveData);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
}
]);
}());
And the template for the modal content:
<div class="modal-header bg-info">
<h3 class="modal-title">Add New Record</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" role="form"></form>
</div>
<div class="modal-footer bg-info">
<button class="btn btn-primary" ng-click="save()">Save</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
My thought is that I'm having issues with scope, but I can't track it down. I have put break points on modalController. The app.controller() call happens when the app loads, I've seen that. But breakpoints within save() and cancel() never get hit.
Can someone help me figure out why the modal's buttons don't do anything?
This turned out to be a stupid mistake. At some point I apparently overwrote the name of one of the other controllers in my project with the same name of the controller I was using for the modal. The other controller did not have save() or cancel() methods so nothing was happening. As soon as I fixed my error and all controllers once again had their proper names this started working again.

Passing parent controller to modal (Angular-ui bootstrap)

I feel like this should work, but it's not. I want to be able to pass the controller that is opening the modal so I can use its submit function etc. I am using the controllerAs pattern (so not using $scope).
var _this = this;
this.openModal = function(modalId,dataIn){
this.modalInstance = $modal.open({
templateUrl: modalId,
controller: 'ModalCtrl',
controllerAs: 'modal',
resolve: {
modalObject: function(){
return dataIn;
},
title: function(){
return 'Training Info';
},
parent: function(){
return _this
}
}
});
_this.modalInstance.result.then(function (data) {
$log.log('submitting data for '+_this.doctorId);
experienceFactory.submitTraining(data).then(function(){
loadExperience();
},function(error){
console.log(error);
});
}, function () {
//something on close
$log.info('Modal dismissed at: ' + new Date());
});
};
this.something = function(){
$log.warn('omg it workt?');
};
That is opened up with a simple aCtrl.openModal('a-modal',aCtrl.data) however for some reason I can't access the parent controller
<script type="text/ng-template" id="a-modal">
<div class="modal-header">
<h3 class="modal-title">{{modal.title}}</h3>
</div>
<div class="modal-body">
<button ng-click="parent.something()">Something</button>
</div>
</script>
The button does nothing, but should be printing the warnings. Any ideas appreciated. Thanks.
Unfortunately you didn't include the code of your controller, however I think that you misunderstood how dependencies are provided to the modal's controller.
The resolve part provides dependencies to the controller, it neither binds them to the scope nor to the controller. Take a look at this JS part of UI-Bootstrap's Modal example:
.controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {
$scope.items = items;
In your case it should be
.controller('ModalCtrl', ['parent', function (parent) {
this.parent = parent;
And in HTML, if you are using controllerAs pattern:
<button ng-click="modal.parent.something()">Something</button>

Resources