Can I stop the transition to the next state in an onExit? - angularjs

I have two states, A and B.
When I exit state A by clicking on a close button I do a transition to screen A using $state.go to state B (screen B)
When I exit state A by clicking on the back browser button on screen A I do a transition to state B (screen B) as the browser URL changes
In the onExit of screen A I do a check and if this fails an Error Dialog opens, clicking Close on the error dialog returns a failed promise to the onExit
However the onExit still goes ahead and I go to screen B
Is it possible to stop the transition from State A (Screen A) to State B (Screen B) if something fails in the onExit?

You can achieve your goal implementing a $stateChangeStart event handler in which you can cancel the state transition (event.preventDefault();) when needed.
Here below is an example where a checkBox simulate a condition of transition disabled. In this case on state change (both state.go and navigation) it opens a modal asking the user to accept/reject the transition blocked (another simulation of some validation check):
var myApp = angular.module('myApp', ['ui.router','ui.bootstrap']);
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/state_a');
$stateProvider
.state('state_a', {
url: '/state_a',
templateUrl: 'stateA.html',
onEnter: function() {
console.log("onEnter stateA");
},
onExit: function($rootScope, $state) {
console.log("onExit stateA: "+$rootScope.chk.transitionEnable);
},
controller: function($scope, $state) {
$scope.goToStateB = function() {
$state.go("state_b");
}
}
})
.state('state_b', {
url: '/state_b',
templateUrl: 'stateB.html',
onEnter: function() {
console.log("onEnter stateB");
},
onExit: function() {
console.log("onExit stateB");
},
controller: function($scope) {
}
});
});
myApp.controller('mainCtrl', function($rootScope, $scope, $uibModal, $state) {
$rootScope.chk = {};
$rootScope.chk.transitionEnable = true;
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams, options) {
if (!$rootScope.chk.transitionEnable) {
event.preventDefault();
$scope.toState = toState;
$scope.open();
} else {
console.log("$stateChangeStart: "+toState.name);
}
})
$scope.open = function () {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModal.html',
scope: $scope,
controller: function($uibModalInstance, $scope) {
$scope.ok = function () {
$uibModalInstance.close('ok');
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
},
size: 'sm'
});
modalInstance.result.then(function (value) {
console.info('Modal closed: ' + value);
}, function () {
console.info('Modal dismissed');
$rootScope.chk.transitionEnable = true;
$state.go($scope.toState.name);
});
};
});
<!DOCTYPE html>
<html>
<head>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.1.1.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.17/angular-ui-router.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="myApp" ng-controller="mainCtrl">
<nav class="navbar navbar-inverse" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" ui-sref="#">AngularUI Router</a>
</div>
<ul class="nav navbar-nav">
<li><a ui-sref="state_a">State A</a></li>
<li><a ui-sref="state_b">State B</a></li>
</ul>
</nav>
<div class="container">
<div ui-view></div>
</div>
<script type="text/ng-template" id="myModal.html">
<div class="modal-header">
<h3 class="modal-title">Title</h3>
</div>
<div class="modal-body">
Transition to <b>{{toState.name}}</b> is disabled, accept or ignore?
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ok()">Accept</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Ignore</button>
</div>
</script>
<script type="text/ng-template" id="stateA.html">
<div class="jumbotron text-center">
<h1>state A</h1>
<p>Example</p>
<a class="btn btn-primary" ng-click="goToStateB()">Goto State B</a>
<a class="btn btn-danger">Do nothing...</a>
</div>
<div class="checkbox">
<label>
<input type="checkbox" ng-model="chk.transitionEnable"> Enable transition
</label>
<pre>chk.transitionEnable = {{chk.transitionEnable}}</pre>
</div>
</script>
<script type="text/ng-template" id="stateB.html">
<div class="jumbotron text-center">
<h1>state B</h1>
<p>The page... </p>
</div>
<div class="container">
Bla bla
<div class="checkbox">
<label>
<input type="checkbox" ng-model="chk.transitionEnable"> Enable transition
</label>
<pre>chk.transitionEnable = {{chk.transitionEnable}}</pre>
</div>
</div>
</script>
</body>
</html>

I answered a similar question where you can prevent the state transition, you might find it useful
$scope.$on('$stateChangeStart') and $modal dialog

#beaver approach definitely works well if the logic decides on the transition to the state B resides in the state A controller.
However if is the case that the state transition to state B requires a pre-condition to be true (regardless of the current state), then using ui-router Resolve could be a cleaner solution.
The business logic for the pre-condition could live in a separate service.
This setup also allows the state B controller to receive the resolved value, if required. And since the resolve function uses promises, the process can be asynchronous as well.
angular.module("yourAppModule")
.service('StateB_helperService', [
'$q',
function($q) {
this.allowTransition = function() {
var deferred = $q.defer();
//
// ... state transition logic ...
//
// resolves the promise to allow the state transition
// rejects otherwise
//
return deferred.promise;
}
}
])
...
angular.module("yourAppModule")
.config([
'$stateProvider',
function($stateProvider) {
$stateProvider.state('state_b', {
templateUrl: "...",
resolve: {
stateB_PreCondition: [
'StateB_helperService',
function(StateB_helperService) {
return StateB_helperService.allowTransition();
}
]
}
})
}
])

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.

Reuse a view as a modal and non-modal (angularjs + bootstrap-ui)

I currently use views/foo.html as a normal view.
Say this view has this:
<p>Hello</p>
Now I want to reuse views/foo.html as the content of a modal, but I'd like to wrap it with this:
<div class="modal-header">
<h3 class="modal-title">Foo</h3>
</div>
<div class="modal-body">
<!-- I want to include views/foo.html in here -->
</div>
So the modal would look like this:
<div class="modal-header">
<h3 class="modal-title">Foo</h3>
</div>
<div class="modal-body">
<p>Hello</p>
</div>
The modal invoker is the following: (notice the comment)
$scope.openFooModal = function () {
var modalScope = $scope.$new();
var modalInstance = $uibModal.open({
templateUrl: 'views/foo.html', /* HERE I NEED TO WRAP IT */
controller: 'fooController',
scope: modalScope,
size: 'lg'
});
modalInstance.result.then(function (result) {
}, null);
};
What is the best solution?
Should I create a foo2.html ?
So at the end the comment made by JB Nizet worked as a start, but there was this issue:
Inject $uibModalInstance to a controllar not initiated by a $uibModal
This is what I did finally:
view in charge of opening the modal or displaying it as an ng-view:
<body ng-controller="indexController">
<ul>
<li>
Open as modal
</li>
<li>
Open as non modal
</li>
</ul>
<div ng-view=""></div> <!-- Used by routeProvider -->
</body>
...its controller
angular.module('myApp').controller('indexController', ['$scope','$uibModal', function($scope,$uibModal) {
$scope.openModal = function () {
var modalScope = $scope.$new();
var modalInstance = $uibModal.open({
templateUrl: 'foo-as-modal.html',
controller: 'fooController',
scope: modalScope
});
modalScope.modalInstance = modalInstance;
// ^ I'm giving the modal his own reference
// using the scope. Injecting wont work on
// the non-modal case!
modalInstance.result.then(function (result) {
}, null);
};
}]);
view to be reused as a modal or as a non-modal:
<p>Hello {{name}}</p>
its controller:
angular.module('myApp').controller('fooController', ['$scope', function($scope) {
// ^
// I'm not injecting
// uibModalInstance
// (this is important)
$scope.name = "John";
$scope.cancel = function () {
$scope.modalInstance.dismiss('cancel');
// ^ I can access the modalInstance by the $scope
};
}]);
view to be used as a modal (wrapper)
<div class="modal-header">
<h3 class="modal-title">I'm a modal</h3>
</div>
<div class="modal-body">
<ng-include src="'foo.html'"></ng-include> <!-- Credits to JB's comment -->
</div>
<div class="modal-footer">
<button class="btn btn-default" ng-click="cancel()">Close</button>
</div>
routeProvider
$routeProvider
.when('/nonmodal', {
templateUrl: 'foo.html',
controller: 'fooController'
})
Here is a plunkr: https://plnkr.co/edit/ZasHQhl6M5cCc9yaZTd5?p=info

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).

AngularJS UI Bootstrap Scope not disposed after modal dismiss

plunker: http://plnkr.co/edit/CrvOFHSfGnXFFWbaXNxn?p=preview
It seems scope for modal is not disposed of after closing the dialog. I have directive that emits when certain div is available, and modal controller receives it. It works fine on first open and close, one emit one receive. On 2nd dialog open and close, one emit and two receives, showing that there are two controller instances, and it goes on for any subsequent dialog open and close.
Is there anyway to make sure to dispose controller scope after modal dialog is dismissed?
html:
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.2.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/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 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body" my-hook>
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</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>
<button class="btn btn-default" ng-click="open('lg')">Large modal</button>
<button class="btn btn-default" ng-click="open('sm')">Small modal</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
</body>
</html>
js:
angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
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.
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, $rootScope, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$rootScope.$on ('MyTestHook', function(event) {
console.log("MyTestHook received");
});
});
angular.module('ui.bootstrap.demo').directive('myHook', function($timeout,$rootScope) {
function link(scope,element,attrs) {
$timeout(function(){
scope.$root.$emit("MyTestHook");
},500);
}
return {
link: link
};
});
This is not the problem of Modal. Modal scope is destroyed completely on dismiss.
Problem is in the code as you have attached $on on $rootScope so every time you click on model it add new listener in $$listeners and listener's count increased by one because $rootscope doesn't get disposed.
$rootScope.$on ('MyTestHook', function(event) { //every call to open modal will add new listener in rootscope
console.log("MyTestHook received");
});
To avoid this use attach $on on scope that disposed on modal dismiss.
See below debugger image.
http://plnkr.co/edit/iR7rGCFgIchsk4sBg26Q?p=preview

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