Model binding not working in Angular UI Bootstrap modal - javascript

I have simple example using Angular UI Bootstrap modal service. In this example I don't understand why model binding is not working. Instead of seeing "Doing something..." on modal dialog I see "{{message}}". What I need to change?
Example is here:
http://plnkr.co/edit/fJhS3e7At11tJTuNSWAB?p=preview
modal html looks like this:
<div ng-app="myModule">
<div ng-controller="modalInstanceController" class="modal-body">
<div>{{message}}</div>
</div>
</div>
And definition of module and controllers:
var myAppModule = angular.module('myModule', ['ui.bootstrap']);
myAppModule.controller('modalInstanceController', function ($scope, $modalInstance, message) {
var vm = this;
vm.message = message;
});
myAppModule.controller('myController', function ($scope, $modal) {
$scope.open = function open() {
var modalInstance = $modal.open({
templateUrl: 'modal.html',
backdrop: 'static',
//windowClass: 'custom-modal-wait',
dialogFade: false,
keyboard: false,
controller: 'modalInstanceController',
resolve: {
message: function () {
return "Doing something ...";
}
}
});
setTimeout(function(){
modalInstance.close('close');
},5000);
}
});

to use the value you pass to the modal, you need to put it on its scope, so set the modal controller as so:
myAppModule.controller('modalInstanceController', function ($scope, $modalInstance, message) {
$scope.message = message;
});
and remove the ng-controller from modal.html, you are already assigning him a controller when you create the modal instance
ng-controller="modalInstanceController"
your fixed example : http://plnkr.co/edit/vnfL72EBMXsQ1NzlJNEF?p=preview

Related

Angular UI Bootstrap modal display during $http request

I am trying to create a directive that uses angular ui bootstrap modal. I would like to open this directive from my controller when a $http request is made, and close it when the request resolves. I'm new to angular and a bit stuck. Here's what I've got so far.
expedition.html controller:
.controller('ExpeditionCtrl', ['$http', 'UserFactory', '$scope',
function ($http, UserFactory, $scope) {
var vm = this;
vm.totalItems;
vm.itemsPerPage = 100;
vm.currentPage = 1;
vm.pageChanged = pageChanged;
vm.content = [];
vm.loadingInstance;
vm.open;
fetchPage();
function pageChanged() {
fetchPage();
}
function fetchPage() {
$http.get('myapi?page=' + vm.currentPage + "&limit=" + vm.itemsPerPage)
.then(function(response) {
angular.extend(vm.content, response.data.content);
vm.content = response.data.content;
vm.totalItems = response.data.totalElements;
})
}
}
expedition.html:
<div class="section">
<div class="sectioncontent">
// some html
<uib-pagination total-items="vm.totalItems" ng-model="vm.currentPage" ng-change="vm.pageChanged()" items-per-page="vm.itemsPerPage"></uib-pagination>
</div>
<loading-modal loadingInstance="vm.loadingInstance" open="vm.open"></loading-modal>
</div>
</div>
loadingModal.directive.js:
.directive('loadingModal', ['$uibModal',
function($modal) {
return {
transclude: true,
restrict: 'EA',
template: '<div ng-init="open()"> Test Loading </div>',
scope: {
loadingInstance: "=",
open: "="
},
link: function(scope, element, attrs) {
scope.open = function(){
scope.loadingInstance = $modal.open({
templateUrl: 'app/templates/loadingModal.tpl.html',
controller: scope.useCtrl,
size: 'sm',
windowClass: 'app-modal-window',
backdrop: true,
});
scope.loadingInstance.result.then(function(){
scope.initialized = true;
console.log('Finished');
}, function(){
scope.initialized = true;
console.log('Modal dismissed at : ' + new Date());
});
};
}
};
}]);
loadingModal.tpl.html:
<div class="modal-body">
Loading ....
</div>
Ok, so I was able to do this by using a factory. Then in the controller, I call LoadingModalFactory.open() when I initiate a $http request, and LoadingModalFactory.modalInstance.close() when the request resolves. Maybe there's a better way to do this, but for now this is working.
.factory('LoadingModalFactory', ['$uibModal', function($uibModal) {
var modalInstance;
var loadingModalFactory = {
open: open,
modalInstance: modalInstance,
};
return loadingModalFactory;
function open() {
loadingModalFactory.modalInstance = $uibModal.open({
templateUrl: 'app/components/modals/templates/loadingModal.tpl.html',
size: 'sm',
windowClass: 'app-modal-window',
backdrop: true,
});
}
}]);
In your fetchPage() function:
Open the modal and return its object to a variable
Run the $http call and in the resolution, close the modal with its stored variable reference
var modal = $uibModal.open({
//your modal config
});
$http.get(...).then(function(response) {
modal.close();
});
I may be going outside of the question, but you don't have to do this in a directive. You can still modularize this by using a template for the modal and a controller for the modal defined elsewhere.
If you need to do this in a directive, you could pass the http get function into the directive with the '&' scope property.

$scope is getting lost while opening a modal on ng-click

When I am trying to open a modal on ng-click the scipe variables is getting lost.
var modalInstance = $modal.open({
templateUrl: 'partials/create.html',
controller: 'AppCreateCtrl',
scope: $scope // <-- I added this
});
You should pass data using the resolve property like this:
var modalInstance = $modal.open({
templateUrl: templateSrv.templateUrl('partials/create.html'),
controller: modalBootstrap,
backdrop: 'static',
keyboard: false,
resolve: {
data: function () {
var result = {};
result.scope = $scope;
return result;
}
}
});
modalInstance.result.then(
function (dataPassedFromModalConroller) {
//this is called when the modal is closed
},
function (dataPassedFromModalConroller) { //Dismiss
//this is called when the modal is dismissed
}
);
Specify the controller for the modal instance like this (we do this in another file):
var modalBootstrap= function ($scope, $modalInstance, data) {
$scope.modalInstance = $modalInstance;
$scope.scope = data.userId;
};
modalBootstrap['$inject'] = ['$scope', '$modalInstance', 'data'];
Your modal template would look something like this:
<div ng-controller="AppCreateCtrl">modal content here</div>

passing objects to modal dialog in AngularJS/bootstrap

I'm trying to pass an object into a modal dialog in a bootstrap/angularJS using the code below. I did this in the style of the answer given at AngularJS UI Bootstrap modal is unable to perform functions from scope. When the modal form is supposed to open from a call to editGroup(), I get the following error:
Error: [$injector:unpr] Unknown provider: selGroupProvider <- selGroup
var EditGroupModalController = function ($scope, $modalInstance, selGroup) {
$scope.user = $sessionStorage.user;
$scope.selGroup = selGroup;
$scope.closeModal = function () {
$modalInstance.close();
};
};
$scope.editGroup = function (selGroup) { // "selGroup" receives the current Group object from $scope.groupList[]
$modal.open({
templateUrl: 'app/views/administration/advanced/editgroup.html',
controller: ['$scope', '$modalInstance','$modal','$sessionStorage','advancedService','selGroup', EditGroupModalController],
size: 'lg',
windowTemplateUrl:'app/views/partials/modaltemplatedraggable.html',
backdrop:'static',
resolve: {
item: function () {
return selGroup;
}
}
});
};
The official description of this error is here; however, I do not understand why I am receiving this error. Any help with this would be greatly appreciated.
Your controller's dependencies list doesn't match controller's function definition: in $modal.open you've listed six dependencies, while in function only three are present.
Dependencies are injected by resolve keys - in your case the key is item.
Necessary changes to your code in order to make it work:
Replace (1)
var EditGroupModalController = function ($scope, $modalInstance, selGroup)
with
var EditGroupModalController = function ($scope, $modalInstance, $modal, $sessionStorage, advancedService, selGroup)
And replace (2)
resolve: {
item: function () {
With
resolve: {
selGroup: function () {
You should name the variable in the resolve as 'selGroup' instead of 'item' so that it can be correctly injected.
Also, the names of the declared dependencies should match the function definition. I put together this simple demo.
angular.module('test', ['ui.bootstrap']).controller('TestController', function($scope, $modal) {
var sel = {name: "A group"};
var EditGroupModalController = function($scope, $modalInstance, selGroup) {
$scope.selGroup = selGroup;
$scope.closeModal = function() {
$modalInstance.close();
};
};
$scope.editGroup = function(selGroup) { // "selGroup" receives the current Group object from $scope.groupList[]
$modal.open({
template: '<div>Test {{selGroup.name}}</div>',
controller: ['$scope', '$modalInstance', 'selGroup', EditGroupModalController],
size: 'lg',
backdrop: 'static',
resolve: {
selGroup: function() {
return sel;
}
}
});
};
});
http://plnkr.co/edit/ec1PjkDZtf4yqINONnX5?p=preview

How to pass form data from angular ui bootstrap modal to view

I'm creating a webapp and I want to implement an option to add friends. I've created the add friend page as a modal with a text input field. I want to test this by displaying the input on my view page. How do I display this data onto my view page?
Here's what I currently have
index.html
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<form name = "addFriendForm">
<input ng-model = "user.name"class="form-control" type = "text" placeholder="Username" title=" Username" />
{{ user.name }}
</form>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
<button class="btn btn-default" ng-click="open()">Add Friend</button>
<div> Username: {{user.name}}</div>
</div>
my JavaScript file:
angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {
$scope.user = {name: ""}
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function () {
$scope.user.name = user.name;}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
});
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance) {
$scope.ok = function () {
$modalInstance.close($scope.user.name);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
plunkr: http://plnkr.co/edit/JIoiNx47KXsY8aqbTUDS?p=preview
Resolve - plunkr
You could make use of modalInstance's resolve property; this acts as the link between the modal instance and the parent controller.
You inject the object in to the ModalInstanceController, and assign it to the scope of your modal instance.
UI Bootstraps resolve works exactly the same as ngRouter's; as such if for whatever reason resolve cannot resolve an object, the modal will not open.
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
user: function() {
return $scope.user;
}
}
});
Scope - plunkr
An alternative, and arguably simpler method would be to pass in the parents scope in to the modal. Note that currently this doesn't work when using controllerAs syntax on the parent controller.
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
scope: $scope
});
I would suggest using the promise from the result to set the value to your controller's variables instead. The "resolve" from my understanding is for passing controller's variable to the dialog for using inside the dialog, not to be changed directly. In your code example, passing result you set in $modalInstance.close() to modalInstance.result.then() will do the trick. In other words, changing line #18 and #19 to the following,
modalInstance.result.then(function (data) {
$scope.user.name = data;
To improve the code a bit, you can actually pass the entire user object to allow adding additional attributes such as email, address, etc. to your user object easily. I had create an example at http://plnkr.co/edit/oztYRNrCRlF1Pw289i1M?p=preview.

How to declare an angular-bootstrap modal in a way that is safe for minimization

I have implemented an angular modal dialog box following the guidelines given at: http://angular-ui.github.io/bootstrap/. The code below works fine when the non-minified files are accessed, but it fails when minification is applied. I have narrowed the problem down to the declaration of the modalInstanceCtrl function below, however I am not clear on how I can implement this function in a minification-friendly manner. I have tried to declare the modalInstanceCtrl function using standard controller syntax, but in that case, the function is not found by the $modal.open call.
The error message that I receive from the minified code is "TypeError: Cannot read property 'value' of undefined".
What is the best way to declare this controller so that it can be both minified as well as called from the $modal.open function?
Any help would be greatly appreciated.
lxModalSupportServices.factory('lxModalSupportService',
function ($modal, $log, $timeout) {
var modalInstanceCtrl = function($scope, $log, $modalInstance) {
$scope.ok = function () {
$modalInstance.close();
};
};
return {
showCameraAndMicrophoneModalWindow : function(scope, htmlTemplate) {
var ModalInstance = $modal.open({
templateUrl: htmlTemplate,
controller: modalInstanceCtrl
});
....
}
});
Change the declaration to
var ModalInstanceCtrl = [
'$scope', '$log', '$modalInstance',
function($scope, $log, $modalInstance) {
$scope.ok = function () {
$modalInstance.close();
};
}
];
and try again. If it still fails, probably the problem is somewhere else.
Normally I would declare the controller for $modal separately:
lxModalSupportServices.controller('AddCommentModalCtrl', ['$scope', function($scope) {
'use strict';
// Implementation...
});
Then use it with string
$modal.open({
templateUrl: htmlTemplate,
controller: 'AddCommentModalCtrl',
});

Categories