Angular bootstrap ui modal scope binding with parent - angularjs

I am having an Angular issue getting a modal scope to unbind from the parent scope. I want the scope object I pass into the modal to be separate from the corresponding scope object.
No matter how I structure the modal object the parent always mirrors it. The only solution I have found is to change the object property names, but that would be cumbersome to do for every modal in my project.
For example, I can have a $scope variable in the parent $scope.parentData.firstName and a modal variable $scope.modalData.a.b.c.firstName, and the parent will mirror the modal value.
I guess there is some parent child $scope issues here that I am not getting.
Here is a plunk illustrating the issue:
http://plnkr.co/edit/5naWXfkv7kmzFp7U2KPv?p=preview
HTML:
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3>I'm a modal!</h3>
</div>
<div class="modal-body">
<input ng-model="modalData.a" />
<input ng-model="modalData.b" />
<input ng-model="modalData.c" />
Selected: <b>{{ sourceData }}</b>
</div>
<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()">Open me!</button>
{{sourceData}}
<div ng-show="sourceData">Selection from a modal: {{ test }}</div>
</div>
</body>
</html>
JS:
angular.module('plunker', ['ui.bootstrap']);
var ModalDemoCtrl = function ($scope, $modal, $log) {
$scope.sourceData = {a:'abc',b:'bcd',c:'cde'};
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
data: function () {
return $scope.sourceData;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.scopeData = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
};
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope, $modalInstance, data) {
$scope.modalData = {};
$scope.modalData = data;
$scope.ok = function () {
$modalInstance.close($scope.modalData);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};

You are passing a reference to your current object, what you want to do is use angular.copy() to pass a deep copy of the object to the modal plnkr:
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
data: function () {
return angular.copy($scope.sourceData); // deep copy
}
}
});

Related

Bootstrap dialog in Angular js

I am new to Angular JS. I started learning Angular JS today. Before I was using jQuery and Bootstrap for front-end. Now I want to show Bootstrap dialog box using AngularJS. I found this, https://angular-ui.github.io/bootstrap/.
But there are so many things difficult for beginners to understand. How can I correct my code to show bootstrap dialog?
This is my code
<html>
<head>
<title>Angular</title>
<link rel="stylesheet" href="http://localhost:8888/angular/bootstrap.css"></link>
<script src="http://localhost:8888/angular/angular-js.min.js"></script>
<script src="http://localhost:8888/angular/angular-js.animate.min.js"></script>
<script src="http://localhost:8888/angular/angular-js.sanitize.min.js"></script>
<script src="http://localhost:8888/angular/ui-bootstrap-tpls.min.js"></script>
</head>
<body>
<div ng-controller="ModalDemoCtrl as $ctrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title" id="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body" id="modal-body">
<ul>
<li ng-repeat="item in $ctrl.items">
{{ item }}
</li>
</ul>
Selected: <b>{{ $ctrl.selected.item }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="$ctrl.ok()">OK</button>
<button class="btn btn-warning" type="button" ng-click="$ctrl.cancel()">Cancel</button>
</div>
</script>
<button type="button" class="btn btn-default" ng-click="$ctrl.open()">Open me!</button>
<button type="button" class="btn btn-default" ng-click="$ctrl.open('lg')">Large modal</button>
<button type="button" class="btn btn-default" ng-click="$ctrl.open('sm')">Small modal</button>
<button type="button" class="btn btn-default" ng-click="$ctrl.toggleAnimation()">Toggle Animation ({{ $ctrl.animationsEnabled }})</button>
<button type="button" class="btn btn-default" ng-click="$ctrl.openComponentModal()">Open a component modal!</button>
<div ng-show="$ctrl.selected">Selection from a modal: {{ $ctrl.selected }}</div>
</div>
</body>
<script>
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($uibModal, $log) {
var $ctrl = this;
$ctrl.items = ['item1', 'item2', 'item3'];
$ctrl.animationsEnabled = true;
$ctrl.open = function (size) {
var modalInstance = $uibModal.open({
animation: $ctrl.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
controllerAs: '$ctrl',
size: size,
resolve: {
items: function () {
return $ctrl.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$ctrl.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$ctrl.openComponentModal = function () {
var modalInstance = $uibModal.open({
animation: $ctrl.animationsEnabled,
component: 'modalComponent',
resolve: {
items: function () {
return $ctrl.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$ctrl.selected = selectedItem;
}, function () {
$log.info('modal-component dismissed at: ' + new Date());
});
};
$ctrl.toggleAnimation = function () {
$ctrl.animationsEnabled = !$ctrl.animationsEnabled;
};
});
// Please note that $uibModalInstance represents a modal window (instance) dependency.
// It is not the same as the $uibModal service used above.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($uibModalInstance, items) {
var $ctrl = this;
$ctrl.items = items;
$ctrl.selected = {
item: $ctrl.items[0]
};
$ctrl.ok = function () {
$uibModalInstance.close($ctrl.selected.item);
};
$ctrl.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
});
// Please note that the close and dismiss bindings are from $uibModalInstance.
angular.module('ui.bootstrap.demo').component('modalComponent', {
templateUrl: 'myModalContent.html',
bindings: {
resolve: '<',
close: '&',
dismiss: '&'
},
controller: function () {
var $ctrl = this;
$ctrl.$onInit = function () {
$ctrl.items = $ctrl.resolve.items;
$ctrl.selected = {
item: $ctrl.items[0]
};
};
$ctrl.ok = function () {
$ctrl.close({$value: $ctrl.selected.item});
};
$ctrl.cancel = function () {
$ctrl.dismiss({$value: 'cancel'});
};
}
});
</script>
</html>
But my code is not working. There are too many options I do not know in this for example "myModalContent.html" is from where? Would you explain step by step to show Bootstrap dialog box in AngularJS?
I tried this way as well
<html>
<head>
<title>Angular</title>
<script src="angular-js.min.js"></script>
<script src="angular-js.animate.min.js"></script>
<script src="angular-js.sanitize.min.js"></script>
<script src="angular-js.touch.min.js"></script>
<script src="bootstrap.ui.js"></script>
<link href="bootstrap.css" rel="stylesheet">
</head>
<body ng-app="MyApp" ng-controller="MyCtrl">
<button class="btn" ng-click="open()">Open Modal</button>
<div modal="showModal" close="cancel()">
<div class="modal-header">
<h4>Modal Dialog</h4>
</div>
<div class="modal-body">
<p>Example paragraph with some text.</p>
</div>
</div>
</body>
<script>
var app = angular.module("MyApp",["ui.bootstrap.modal"]);
app.controller('MyCtrl',function($scope){
$scope.open = function() {
$scope.showModal = true;
};
})
</script>
</html>
It shows like this:
It is not working as well. How can I show bootstrap dialog in AngularJS?
You don't have a ctrl.open function although you ref one in your ng-click.
Maybe you can try this?
$ctrl.open = function (size) {
var modalInstance = $uibModal.open({
animation: $ctrl.animationsEnabled,
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
controllerAs: '$ctrl',
size: size,
resolve: {
items: function () {
return $ctrl.items;
}
}
});
open() method returns a modal instance. This is what actually creates the modal on your template.
templateurl is a path to your template. Here, its looking for myModalContent.html in the same path as your controller code. You need to create and design the template and that will get loaded when this modal is called in your view.
template can be used here instead of templateurl for inline HTML if you do not have enough HTML. "enough" is subjective to your understanding.
controller is the name of your controller. You can define it as you like.
controllerAs is the alias of your controller. You can define it to be what you like too. $ctrl is the alias of your controller by default. If you remove the controllerAs option from here, you can still use $ctrl in your template. Although, using this requires you to have controller option provided.
animationsenabled is a boolean value which can be used to toggle modal animation in your view by toggling the animation property. Default is false.
resolve helps create a $resolve object on the opened modal. This helps provide all resolved values from your items. Its basically a configuration on the $routeprovider service of Angular. To help understand $resolve better, you can have a look at this
Since you are new to Angular, much like me, a great place to start would be to understand Services in Angular. Its going to be one of your most used feature.
Moreover, you can check out plunker of the above code, edit it and understand the functioning. I tried it yesterday for the first time too.
Also, add angular-ui as a tag to your question so the angular-ui guys can get involved.
Hope this helps in some way.

Angular Modal - closing/dismissing modal

I am new to Angular and trying to implement a modal. Having problem closing/dismissing the modal - when I click the cancel button, nothing happens.
Here is the controller code:
angular.module('navApp')
// Passing the $modal to controller as dependency
.controller('HomeCtrl', ['$scope', '$uibModal', function ($scope, $uibModal) {
$scope.title = "Hello, Angm-Generator!";
$scope.open = function () {
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalCtrl'
});
};
}])
.controller('ModalCtrl', function ($scope, $uibModalInstance) {
// Added some content to Modal using $scope
$scope.content = "ModalCtrl, Yeah!"
// Add cancel button
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
})
and here is the template view of the actual modal
<!-- Modal Script -->
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<button type="button" class="close" datadismiss="modal" aria-hidden="true">×</button>
<h3 class="modal-title">Hello from Modal!</h3>
</div>
<div class="modal-body">
Modal Content from: <b>{{ content }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-danger" ngclick="cancel()">Cancel</button>
</div>
</script>
Even clicking the cross on the top right of modal doesn't close the modal. Any ideas? Thanks:)
Should it not be ng-click="cancel()" instead of ngclick?
Also I don't think the scope is bound to the controller, I haven't tested this but I believe you need some more options:
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalCtrl',
controllerAs: '$mCtrl',
bindToController: true
});
And then just update your template:
ng-click="$mCtrl.cancel()"
Have you tried $uibModalInstance.close()?
Another thing you can do is
$scope.open = function () {
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalCtrl'
});
modalInstance.result.then(function successCallBack() {
modalInstance.close()
}, function errorCallBack() {
modalInstance.close()
})
};`
If you want to close the model , on click of the cross bar then , you can use
<button type="button" class="close" data-dismiss="modal">×</button>
This will be button , and data-dismiss="modal" will close your modal.

Unable to make angular-formly work within a ng-template of an angular-ui-bootstrap modal

I am using angular-formly to build a form inside an angular-ui-bootstrap modal, the following code works when the form is placed outside the modal template but it doesn't when placed inside the ng-template, it just doesn't print the fields at all.
I believe this should work but I don't know how the life-cycle of angular-formly runs, so I am unable to identify how to make the fields show up inside my bootstrap modal template.
The issue is clearly related to the ng-template, it appears not to render the form even if the fields array is passed correctly.
var app = angular.module("demo", ['dndLists', 'ui.bootstrap', 'formly', 'formlyBootstrap']);
app.controller('ModalInstanceCtrl', function ($scope, $uibModalInstance, items, User) {
var vm = this;
vm.loadingData = User.getUserData().then(function(result) {
vm.model = result[0];
vm.fields = result[1];
vm.originalFields = angular.copy(vm.fields);
console.log(vm);
});
});
app.controller("AdvancedDemoController", function($scope, $uibModal){
$scope.modalOpen = function(event, index, item){
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: 'md',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
});
In my view:
<!-- Template for a modal -->
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<div ng-if="vm.loadingData.$$state.status === 0" style="margin:20px 0;font-size:2em">
<strong>Loading...</strong>
</div>
<div ng-if="vm.loadingData.$$status.state !== 0">
<form ng-submit="vm.onSubmit()" novalidate>
<formly-form model="vm.model" fields="vm.fields" form="vm.form">
<button type="submit" class="btn btn-primary submit-button">Submit</button>
</formly-form>
</form>
</div>
<ul>
<li ng-repeat="item in items">
{{ item }}
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</div>
</script>
Any ideas?
When calling $uibModal.open you need to specify controllerAs: 'vm' (that's what you're template assumes the controller is defined as).

Angular modal- the modal is displayed from the start and I can't hide it

I am new to angular js
I have to open a modal dialog which display some selected value.
Open Modal
<div modal="showModal" close="cancel()">
<div class="modal-header">
<h4>Modal Dialog</h4>
</div>
<div class="modal-body">
<p>E{{inputValue}}</p>
</div>
<div class="modal-footer">
<button class="btn btn-success" ng-click="ok()">Okay</button>
<button class="btn" ng-click="cancel()">Cancel</button>
</div>
</div>
The controller for the module which contain the modal is:
var app = angular.module('myApp', ['ui.bootstrap.modal']);
app.controller('ctrlTags', function($scope){
$scope.inputValue=$('input:checked').val()
$scope.open = function() {
$scope.showModal = true;
return $scope.inputValue;
};
$scope.ok = function() {
$scope.showModal = false;
};
$scope.cancel = function() {
$scope.showModal = false;
};
});
For some reason the modal is displayed as is it is a regular part of the page (doesn't function as a modal)
Toggling a boolean is not how ui-boostrap modals are opened. See documentation. Basically you have to call $uibModal.open with a template:
$scope.open = function() {
var modalInstance = $uibModal.open({
templateUrl: 'myModal.html',
controller: 'ModalInstanceCtrl'
});
}
Have a look at this plunker where I'm passing a value to the modal, through the resolve property of $uibModal.open.

Why does $modal introduce an extra scope for the form?

I've managed to use the example from angular-ui-bootstrap to demonstrate the problem (but you need the console open to see it) Plnkr link to this code
Why is the form being stuck in a sub scope instead of this $scope?
The HTML
<!doctype html>
<html ng-app="plunker">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.js"></script>
<script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="ModalDemoCtrl">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3>I'm a modal!</h3>
</div>
<div class="modal-body">
<ng-form name="myForm">
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</ng-form>
</div>
<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()">Open me!</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
</body>
</html>
** The Javascript **
angular.module('plunker', ['ui.bootstrap']);
var ModalDemoCtrl = function ($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
};
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
console.log("The form in the $scope says: ", $scope.myForm);
console.log("The form in the $scope.$$childTail says: ", $scope.$$childTail.myForm);
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
The ng-form is not in the $scope where I would expect it to be, even though the other $scope items are there. What is the cause of the nested scope for the form (that is added by angular for form validation).
The output from the console looks like:
The form in the $scope says: undefined example.js:37
The form in the $scope.$$childTail says:
Constructor {$error: Object, $name: "myForm", $dirty: false, $pristine: true, $valid: true…}
If you do not specify a scope property on $modal.open it take $rootscope. This is from documentation
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 provided
scope). Defaults to $rootScope
so set scope before call
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
scope:$scope,
resolve: {
items: function () {
return $scope.items;
}
}
});
If you want to access the $scope declared on your main controller and make it accessible to the modal you have to include in your modal configuration.
scope: $scope
Just like what Chandermani put up on his answer above.
This is because transclusion used in modals which creates new scope for form. I am defining forms this way:
<form name="$parent.myForm">
Then you can use $scope.myForm in modal controller.

Resources