I have a bootstrap modal which has a single ok and cancel button wired. What I need help with is I need a different instance of ok and cancel for every modal instance that is called.
Modal.html
<div ng-controller="dealerController">
<div class="modelstitle">
<div class="modal-header mdlheader">
<button type="button" class="close close-btn" ng-click="cancel()">×</button>
<h3 class="modal-title mdltitle" ng-model="modalTitle">{{modalTitle}}</h3>
</div>
<div class="modal-body mdlbody">
<p ng-model="modalContent">{{modalContent}}</p><br/>
</div>
<div class="modal-footer footerbtn">
<button class="btn btn-primary btnwarning" type="button" ng-click="cancel()">Cancel</button>
<button class="btn btn-primary btnwarning" type="button" ng-click="ok()">OK</button>
</div>
</div>
Controller
var myApp=angular.module('home', ['ui.bootstrap']);
myApp.controller('ModalController',function($scope,$uibModal){
$scope.showModal = function(){
$scope.modalInstance = $uibModal.open({
animation: true,
templateUrl: 'modal.html',
//controller: 'ModalController',
size: 'sm',
scope: $scope,
// Prevent closing by clicking outside or escape button.
backdrop: 'static',
keyboard: false
});
}
$scope.ok = function(){
$scope.modalInstance.dismiss();
}
$scope.cancel = function() {
//alert("Cancel from main controller");
$scope.modalInstance.dismiss('cancel');
};
})
Plunker
Expected: I need a different ok and cancel implementation for every instance of a modal.
You could make your modal opening logic more generic and pass ok and cancel functions to it and use those in modal's controller.
<button ng-click="showSomeModal()">Modal 1</button>
<button ng-click="showOtherModal()">Modal 2</button>
angular.module('home', ['ui.bootstrap'])
.controller('ModalController',function($scope,$uibModal){
function openModal(ok, cancel) {
$uibModal.open({
animation: true,
templateUrl: 'modal.html',
size: 'sm',
backdrop: 'static',
keyboard: false,
controller: function($scope) {
$scope.ok = function() {
$scope.$close();
ok();
};
$scope.cancel = function() {
$scope.$dismiss();
cancel();
};
}
});
}
angular.extend($scope, {
modalTitle: 'I am a Title',
modalContent: 'I am model content',
showSomeModal: function() {
openModal(angular.noop, angular.noop);
},
showOtherModal: function() {
function ok() {
console.log('ok');
}
function cancel() {
console.log('cancel');
}
openModal(ok, cancel);
}
});
});
Related plunker here https://plnkr.co/edit/6ecoHA
Or instead of using controller, you could use those same functions after modal is closed/dismissed, using modal result.
function openModal(ok, cancel) {
$uibModal.open({
// remove controller altogether
...
})
.result
.then(ok) // closed
.catch(cancel); // dismissed
}
// changes in modal template
<button type="button" ng-click="$close()">OK</button>
<button type="button" ng-click="$dismiss()">Cancel</button>
You can try add extra parametr to you modal instance that will identity your actual opened modal. Then in ok and cancel function do if statement.
var myApp=angular.module('home', ['ui.bootstrap']);
myApp.controller('ModalController',function($scope,$uibModal){
$scope.showModal = function(modalId){
$scope.modalInstance = $uibModal.open({
animation: true,
templateUrl: 'modal.html',
//controller: 'ModalController',
size: 'sm',
scope: $scope,
// Prevent closing by clicking outside or escape button.
backdrop: 'static',
keyboard: false,
});
$scope.modalInstance.modalNameProperty = modalId ;
}
$scope.ok = function(){
if( $scope.modalInstance.modalNameProperty == somename){
//do somethink
}
else if($scope.modalInstance.modalNameProperty == somename)
{
// do other staff
}
$scope.modalInstance.dismiss();
}
The same in cancel function.
Related
I must be missing something here. I have a module like below:
(function (app) {
'use strict';
app.controller('modalCtrl', modalCtrl);
modalCtrl.$inject = ['$scope', '$modalInstance'];
function modalCtrl($scope, $modalInstance) {
$scope.closeModal = closeModal;
function closeModal() {
$modalInstance.dismiss();
}
}
})(angular.module('mainModule'));
I call the closeModal function from this vew:
<div class="panel panel-primary">
<div class="panel-heading">
Heading!
</div>
<div class="panel-body">
Some message.
</div>
<div class="panel-footer clearfix">
<div class="pull-right">
<button type="button" class="btn btn-danger" ng-click="closeModal()">OK</button>
</div>
</div>
</div>
Modal opens as expected, however it cannot be closed by clicking ok button. The code opening modal is below:
function openDialog() {
$modal.open({
templateUrl: 'modal.html',
controller: 'modalCtrl',
scope: $scope
}).result.then(function ($scope) {
//some code here
}, function () {
});
}
EDIT:
openDialog function is in different controller than closeModal. Nothing seem to work below. To me it appears as if ng-click on closeModal doesn't find its controller to invoke closeModal, however there is no error thrown for this.
Try opening the modal like this:
function openDialog() {
$modal.open({
templateUrl: 'modal.html',
controller: 'modalCtrl',
scope: this.$new()
}).result.then(function ($scope) {
//some code here
}, function () {
});
}
Create a instance of your modal first
function openDialog() {
$scope.modal = $modal.open({
templateUrl: 'modal.html',
controller: 'modalCtrl',
scope: $scope
}).result.then(function ($scope) {
//some code here
}, function () {
});
}
function closeModal() {
$scope.modal.dismiss();//or close();
}
$scope.closeModal = function() {
$scope.$modalInstance.dismiss('cancel');
};
Did you try using the data-dismiss="modal" attribute?
remove scope:$scope from openDialg function
function openDialog() {
$modal.open({
templateUrl: 'modal.html',
controller: 'modalCtrl'
}).result.then(function ($scope) {
//some code here
}, function () {
});
}
I am new to Angular. I have created a component with a template (panel.html) and a controller (allPanelsRetrieved). When a specific button defined in the template is clicked, the showDetails() function specified in the controller is called. This function triggers the opening of a modal dialog specified by a template (panel-list.details-template.html) and a controller, which are both defined inside the allPanelsRetrieved controller. The problem is that the modal dialog is displayed but the controller doesn't work (the click of the OK button does nothing). Where the problem may be? Thanks in advance
angular.
module('panelList')
.component('panelList', {
templateUrl: '/panel-list/panel.html',
controller: ['Panel', 'NgTableParams','$scope', '$location', '$uibModal',
function PanelListController(Panel, NgTableParams, $scope, $location, $uibModal) {
this.allPanelsRetrieved = (index, before) => {
//..hidden code here
}
this.showDetails = function () {
$uibModal.open({
templateUrl: '/panel-list/panel-list.details-template.html',
controller: function ($uibModalInstance) {
let $ctrl = this;
$ctrl.ok = function () {
$uibModalInstance.close();
};
},
}).result.then(
function (success) {
alert(success);
},
function (error) {
alert(error);
}
);
};
}]
});
Here is the template panel-list.details-template.html:
<div>
<script type="text/ng-template" id="/panel-list/panel-list.details-template.html">
<div class="modal-header">
<h3 class="modal-title">Modal title</h3>
</div>
<div class="modal-body">
Modal content
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="$ctrl.ok()">Close</button>
</div>
</script>
Use $scope to make it work in the AngularJS way. Here is a working plnkr demo of what you try to achieve.
$uibModal.open({
templateUrl: '/panel-list/panel-list.details-template.html',
controller: function ($uibModalInstance, $scope) {
$scope.ok = function () {
$uibModalInstance.close();
};
}
}).result.then(
function (success) {
alert(success);
},
function (error) {
alert(error);
}
);
View
<script type="text/ng-template" id="/panel-list/panel-list.details-template.html">
<div class="modal-header">
<h3 class="modal-title">Modal title</h3>
</div>
<div class="modal-body">
Modal content
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">Close</button>
</div>
</script>
While the angular.component implementation provides a default for the controllerAs syntax...
controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
...it appears that angular-ui-bootstrap does not.
Simply provide a value for controllerAs in your $uibModal options to continue using the preferred syntax.
$uibModal.open({
templateUrl: '/panel-list/panel-list.details-template.html',
controllerAs: '$ctrl',
controller: function($uibModalInstance) {
let $ctrl = this;
$ctrl.ok = function () {
$uibModalInstance.close();
}
}
http://plnkr.co/edit/q1arN18553XoUZEuPcPl?p=preview
The problem is with this keyword as you are using it. Use arrow function instead and it will work:
$uibModal.open({
templateUrl: '/panel-list/panel-list.details-template.html',
controller: ($uibModalInstance) => {
let $ctrl = this;
$ctrl.ok = function () {
$uibModalInstance.close();
};
},
})
I have the following code
$scope.currentTask = undefined;
$scope.openModal = function (task, size, parentSelector) {
var parentElem = parentSelector ?
angular.element($document[0].querySelector('.modal-demo ' + parentSelector)) : undefined;
var modalInstance = $uibModal.open({
animation: true,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
controller: 'homeController',
controllerAs: '$ctrl',
scope: $scope,
size: size,
appendTo: parentElem,
resolve: {
items: function () {
return $scope.items;
}
}
});
$rootScope.currentModal = modalInstance;
$rootScope.currentModal.result.then(function () {
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
}
$scope.setTask = function(task) {
$scope.currentTask = task;
}
$scope.log = function (currentTask) {
console.log($scope.currentTask);
}
<div class="row" ng-init="processPages()">
<div class="panel panel-default col-xs-3" style="margin: 20px" ng-repeat = "list in pages[currentPage]">
<div class="panel panel-default">
<div class="panel-heading">
<h6 style = "float: right">({{list.tasks.length}})</h6>
<div class="panel-title">
<h4>{{list.name}}</h4>
</div>
</div>
</div>
<div class="panel-body">
<table class="table table-striped table-hover" ng-init = "tasks = list.tasks">
<tr ng-repeat="task in tasks">
<td ng-click="setTask(task); openModal(task);>
<h5>{{task.name}}</h5>
</td>
</tr>
</table>
</div>
</div>
</div>
<script type="text/ng-template" id="myModalContent.html">
<div ng-init="editEnabled = false">
<div class="modal-header" ng-init = "log(currentTask)">
<h3 class="modal-title" id="modal-title" ng-show = "!editEnabled">Not editing</h3>
<h3 class="modal-title" id="modal-title" ng-show = "editEnabled">Editing</h3>
</div>
<div class="modal-body" id="modal-body">
<div ng-show="!editEnabled">
</div>
<div ng-show="editEnabled">
</div>
</div>
<div class="modal-footer">
<button style = "float: left" class="btn btn-primary" type="button" ng-show = "!editEnabled" ng-click="editEnabled = true">Editar</button>
<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
</div>
</script>
Here's how the page is working:
First we have a list of tasks and if we click on one task...
...we get a model
I'd like the task information to be passed to the model, but everytime I set the task on the $scope to be the task on the list, even though it happens before the model is opened the log function prints the currentTask is still undefined. I've tried to change the currentTask definition at the beggining to be something concrete, but what happens then is the log function prints what was defined at the beggining and not after the change is made.
The only solution I could find that worked was creating a different controller for the modal and sharing data between modalController and homeController via service. It's working fine, here's the service:
var app = angular.module('agendaApp');
app.service('sharedModalProperties', function() {
var task = undefined;
var activeModal = undefined;
return {
setCurrentTask : function (task) {
this.task = task;
},
getCurrentTask : function () {
return this.task;
},
setActiveModal : function (modal) {
this.modal = modal;
},
getActiveModal : function () {
return this.modal;
}
}
});
The task being undefined indicates the modal popup's ($scope) is not aware of any such model data. I assume its creating a fresh scope object, so your call to setTask() does not work as it is working on old scope. You can try calling during your modal display code.
$scope.openModal = function (task, size, parentSelector) {
var parentElem = parentSelector ?
angular.element($document[0].querySelector('.modal-demo ' + parentSelector)) : undefined;
var modalInstance = $uibModal.open({
animation: true,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
controller: 'homeController',
controllerAs: '$ctrl',
scope: $scope,
size: size,
appendTo: parentElem,
resolve: {
items: function () {
return $scope.items;
}
}
});
$rootScope.currentModal = modalInstance;
$rootScope.currentModal.result.then(function () {
}, function () {
$log.info('Modal dismissed at: ' + new Date());
}
//Add this code
$scope.currentTask = task;
//Or Call Set Task Here.
setTask(task);
);
}
From our discussion in the comments try something like this for your uibmodal's controller (See the git repo for the changes I made)
...
$scope.items = ["items1", "items2", "items3"];
var modalInstance = $uibModal.open({
animation: true,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
size: size,
appendTo: parentElem,
resolve: {
modalItems: function() {
console.log("items to send to modal", $scope.items);
return $scope.items;
}
},
controller: ['$scope', 'modalItems', function($scope, modalItems) {
console.log("items sent to modal", modalItems);
$scope.modalItems = modalItems;
}]
});
...
HTML:
<script type="text/ng-template" id="myModalContent.html">
{{modalItems}} <!-- Should show the array of items -->
</script>
I would like to use the ui-bootsrap Modal with the AngularJS Fullstack Generator & ES6, but it doesn't work.
I would like to choose a Project, click "Edit" and edit the Project in a large Modal. But I don't get the modal to open.
In the Console, I get this error Message:
"Error: $modal is not defined"
My Project Controller looks like this:
'use strict';
(function() {
class ProjectCtrl {
constructor(Project, $modal, $log) {
this.project = Project;
this.projects = [];
this.getAllProjects(Project);
this.$modal = $modal;
this.log = $log;
}
// Open a modal window to Update a single Project
modalUpdate(size, selectedProject) {
var modalInstance = $modal.open({
templateUrl: 'app/project/project-edit.modal.html',
controller: function ($scope, modalInstance, aProject) {
$scope.project = aProject;
},
size: size,
resolve: {
aProject: function () {
return selectedProject;
}
}
});
modalInstance.result.then(function (selectedItem) {
this.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
}
angular.module('projectApp')
.controller('ProjectCtrl', ProjectCtrl);
})();
app.js looks like this:
'use strict';
angular.module('projectApp', [
'projectApp.constants',
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router',
'ui.bootstrap'
])
.config(function($urlRouterProvider, $locationProvider) {
$urlRouterProvider
.otherwise('/');
$locationProvider.html5Mode(true);
});
The Button to open the Modal:
<button type="button" class="btn btn-default btn-xs pull-right" ng-click="ProjectCtrl.modalUpdate('lg', project)"><span aria-hidden="false"></span> Edit</button>
My guess is that in ProjectCtrl, I have somehow to $inject 'Project', '$modal' & '$log', but I don't know how and where.
I solved the Modal problem in another way, cause it seems that UI Bootstrap doesn't work in ES6. At least not now.
I used the Modal Service here for Angular-Fullstack.
Here is a simple example with a delete Modal:
'use strict';
(function() {
class AdminController {
constructor(User, Modal) {
// Use the User $resource to fetch all users
this.users = User.query();
this.modal = Modal;
}
delete(user) {
var deleteConfirmationModal = this.modal.confirm.delete((user) => {
user.$remove();
this.users.splice(this.users.indexOf(user), 1);
});
deleteConfirmationModal(user.name, user);
}
}
angular.module('sampleApp.admin')
.controller('AdminController', AdminController);
})();
This is how the Modal looks like:
Which version of ui-bootstrap are you using ?
The syntax is different depending on which version you're using.
Assuming you're using v0.13.4 or older and without ES6, here the solution :
NOTE :
If you're using more recent version than v0.13.4 then replace $modal by $uibModal and $modalInstance by $uibModalInstance and it should work too.
First, what you need to do is write in the command line :
yo angular-fullstack:controller MyModalName
then in myModalName.controller.js put this :
.controller('MyModalNameCtrl', function ($scope,$modal) {
$scope.openModal = function () {
var modalInstance = $modal.open({
animation: true,
templateUrl: 'testmodal',
controller: 'ModalInstanceCtrl',
});
modalInstance.result.then(function () {}, function () {
console.log('Modal dismissed at: ' + new Date());
});
};
});
Then still in myModalName.controller.js put below :
//change theNameOfYourApp to your corresponding app name !
angular.module('theNameOfYourApp').controller('ModalInstanceCtrl', function ($scope, $modalInstance) {
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
Then last step, in your .html page where you want to display the modal, put :
<!--Modal Template-->
<div ng-controller="MyModalNameCtrl">
<script type="text/ng-template" id="testmodal">
<div class="modal-header">
<h3 class="modal-title">Hello :</h3>
</div>
<div class="modal-body">
<p>hey, this is the body </p>
</div>
<div class="modal-footer">
<button class="btn btn-default" type="button" ng-click="ok()">OK</button>
<button class="btn btn-default" type="button" ng-click="cancel()">Cancel()</button>
</div>
</script>
</div>
I'm creating a simple update modal. To do so, I'm passing a parameter into my angular-bootstrap modal. I've two controllers, ModalCtrl and ModalInstanceCtrl:
adminController.controller('ModalCtrl', ['$scope', '$modal', '$log', 'Profile',
function ($scope, $modal, $log, Profile) {
$scope.open = function (profile) {
var modalInstance = $modal.open({
animation: true,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
profile: function () {
$log.info(profile);
return profile;
}
}
});
modalInstance.result.then(function (updatedProfile) {
$log.info(updatedProfile);
Profile.post(updatedProfile);
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
}]);
adminController.controller('ModalInstanceCtrl', function ($scope, $modalInstance, profile) {
$scope.ok = function () {
$modalInstance.close(profile);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
The profile is logged both when opening and accepting the modal - leading me to believe that it's being passed into the instance without issue. However, displaying the modal doesn't display anything from that profile object:
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">Profile View</h3>
</div>
<div class="modal-body">
<div><p>{{profile.profileType}}</p></div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
</script>
What am I doing wrong?
You need to put the profile object on the $scope for it to be accessible in the HTML template:
adminController.controller('ModalInstanceCtrl', function ($scope, $modalInstance, profile) {
$scope.profile = profile;
$scope.ok = function () {
$modalInstance.close(profile);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});