Using a controller as uibModal Controller - angularjs

So I am working on a module called "ShowTree".
Before this, I have a controller named "InviteUserCtrl". Inside the ShowTree module, there is a button that will show a uibModal that is used to add new user.
Basically this uibModal in ShowTreeCtrl is all exactly the same as InviteUserCtrl. So, instead of copy pasting all the code from the InviteUserCtrl to the new uibModalController, I decided to inject the InviteUserCtrl as the uibModalController.
The problem is I can't use the InviteUserCtrl as my uibModalController
here is my html code in ShowTree list.html
<div ng-controller="inviteUserCtrl as vm">
<script type="text/ng-template" id="inviteUser.html">
<div class="modal-header">
<h3 class="modal-title">Invite User</h3>
</div>
<div class="modal-body">
<span ng-include="'app_view/modules/invite_user/form.html'"></span>
<br><br>
</div>
<div class="modal-footer">
<button class="btn btn-warning" type="button" ng-click="vm.cancel()">Back</button>
</div>
</script>
</div>
here is the code in my ShowTreeCtrl
function open(size){
var modalInstance = $uibModal.open({
animation : true,
templateUrl: 'inviteUser.html',
controller: 'inviteUserCtrl as vm',
size: size,
});
}
Also i am using ui-router. here is my code in the router
.state('app.show_tree', {
url: '/show_tree/:action/:id',
templateUrl: base_view_url+'modules/show_tree/index.html',
data : { title: 'Show Tree' },
controller : "showTreeCtrl",
controllerAs : "vm",
resolve: load([
base_view_url+'modules/show_tree/showTreeCtrl.js',
base_view_url+'modules/invite_user/inviteUserCtrl.js',
'ui.select'
]),
params : {action:"list",id:null},
activetab: 'Activity'
})
The above code is able to display the form from the InviteUser module, but the controller seems doesn't work. The form button and the controller API do not run at all.
What am I missing here? thank you ..

Related

AngularJs UI Modal without $scope and extra ModalController (resolve)

I want to implement UI Modal in AngularJS without using $Scope and without implementing the ModalController(resolve).
I am not using $scope in my Controller. I am using vm = this. So I dont know what value to assign to scope while openinig the Modal.
I also dont want to use resolve, as it involves creating one more Controller.
Please find my code below: Any help will be greatly appreciated.
HTML
<script type="text/ng-template" id="modaltemplate.html">
<div class="modal-header">
<h3>Modal Header</h3>
</div>
<div class="modal-body">
<p>Modal Body</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="vm.close()" data-dismiss="modal">Close
</button>
</div>
</script>
CONTROLLER Look at scope in $uibModal.open() function.
angular
.module("app", ["ui.bootstrap"])
.controller("MyController", MyController)
MyController.$inject = ["$uibModal"];
function MyController($uibModal) {
var vm = this;
vm.open = open;
vm.close = close;
function open() {
vm.modalInstance = $uibModal.open({
templateUrl: 'modaltemplate.html',
scope: //what should I assign here, I dont want to use $scope. Or in other words, I want to assign 'vm' here.
});
}
function close() {
//This function is not getting called as it does not understand the vm.
}
}
I have tried the following things:
In the HTML, set ng-controller="MyController as vm".
Also tried setting various Values for scope, controller, and controllerAs in the $uibModal.open() function.
But nothing seems to working. Can anybody please help me out.
if you have problem with Close function, you can set $dismiss() for close modal instance, also you can pass parameter in $dismiss function for further use, try this:
<script type="text/ng-template" id="modaltemplate.html">
<div class="modal-header">
<h3>Modal Header</h3>
</div>
<div class="modal-body">
<p>Modal Body</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$dismiss('cancel')" data-dismiss="modal">Close
</button>
</div>
</script>
You can create a new scope in main controller
var modalScope = $scope.$new();
assign what you need on new scope (or whole vm):
modalScope.vm = vm;
and then assign it as modal scope:
vm.modalInstance = $uibModal.open({
templateUrl: 'modaltemplate.html',
scope: modalScope
});
Just make sure you clear it when closing/destroying modal
modalScope.vm = null;

Array not outputting in modal

I can't figure out why the content in my array isn't outputting in the modal.
I'm doing a ng-repeat. the buttons are pulling from the array, but the content inside the modal is blank. Can anyone tell me whey?
Here's a jsfiddle:
http://jsfiddle.net/8s9ss/203/
<div ng-app="app">
<div ng-controller="RecipeController">
<div ng-repeat="recipe in ChickenRecipes">
<button class="btn btn-default" ng-click="open()">{{ recipe.name }}</button> <br />
<!--MODAL WINDOW-->
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3>Recipe: {{ recipe.name }}</h3>
</div>
<div class="modal-body">
Recipe Content<br />
{{ recipe.cookTime }}
{{recipe.directions}}
</div>
<div class="modal-footer">
</div>
</script>
</div>
</div>
</div>
$modal create a child scope (and default is child of $rootScope) for the modal
So what you need is something like this:
$scope.open = function (recipe) {
$scope.recipe = recipe;
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
scope: $scope,
});
};
And:
<button class="btn btn-default" ng-click="open(recipe)">{{ recipe.name }}</button> <br />
P/s: It's better to use $modal's resolve and controller option (pass the resolved data to the new controller)
You are mixing up some concepts, putting the modal template inside the ng-repeat won't do a thing. That's not how modals work.
First, remove the template from the ng-repeat and put it elsewhere.
Then, you must create a controller for your modal:
app.controller('RecipeModalController', function($scope, $modalInstance, $modal, item){
$scope.recipe = item;
console.log(item);
});
And pass the recipe you want to open as a parameter on ng-click:
$scope.open = function (recipe) {
var modalInstance = $modal.open({
controller: 'RecipeModalController',
resolve: {item: function() {return recipe} },
templateUrl: 'myModalContent.html',
});
};
I've updated the fiddle to show it: http://jsfiddle.net/8s9ss/204/

Angular UI: field entered in Modal is undefined in controller

Please run this plunker, if you enter a value in the modal and then click on show value, the value is undefined in $scope, how to get the value?
HTML
<div ng-app="app" ng-controller="myCtl">
<input type="button" ng-click="openModal()" value="Open Modal">
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h4 class="modal-title">The Title</h4>
</div>
<form name="myForm" novalidate>
Enter a value <input type="text" ng-model="someField" />
</form>
<div class="modal-footer">
<button ng-click="showValue()">Show value</button>
</div>
</script>
</div>
Javascript
var app = angular.module('app', ['ui.bootstrap']);
app.controller('myCtl', function($scope,$uibModal) {
$scope.openModal = function() {
$scope.modalInstance = $uibModal.open({
animation: false,
templateUrl: 'myModalContent.html',
scope: $scope
});
};
$scope.showValue = function() {
alert('value entered=' + $scope.someField);
};
});
You are seeing this because the scope of the modal is isolated. Even though you pass the $scope to modal. It still does not use the same $scope.
For your example the following would work.
Update the modal template:
<button ng-click="showValue(someField)">Show value</button>
Update your controller showValue method as follows:
$scope.showValue = function(theValue) {
$scope.someField = theValue;
alert('value entered=' + $scope.someField);
};
Really though the best way to use the modal is to use the modal instance created by the open method to track the close and dismiss events and handle the result that way. Take a look at the example on on the ui-modal section of the ui-bootstrap documentation

How to use 1 ui-view if there are multiple ui-view elements with the same name?

I have a html structure like so,
<div class="content-wrapper">
<div class="content">
Click me
</div>
<div ui-view="content-view">Template goes here</div>
</div>
<div class="content-wrapper">
<div class="content">
Click me
</div>
<div ui-view="content-view">Template goes here</div>
</div>
Two content-wrapper divs with both a ui-view called content-view.
And my state config looks like this,
$stateProvider
.state('home', {
url: ''
})
$stateProvider
.state('content-view', {
url: '',
views: {
"content-view": {
template: '<div>Content</div>',
}
},
})
See it in action here > http://plnkr.co/edit/997KbH9beLLHClM0IKb9?p=preview
If a user clicks on one of two ui-sref elements both the ui-view 'content-view` elements get triggered and inject the template.
What I would like to see is that only the ui-view in the content-wrapper element that gets clicked gets triggered.
Hiding one or the other element wouldn't be a good solution, because then the views will still have to load all the data in them. So I think my best bet is to target the specific ui-view in the same content-wrapper element.
* Update *
I've updated my plunker > http://plnkr.co/edit/997KbH9beLLHClM0IKb9?p=preview
I create several rows with content divs in them. Each row has 1 ui-view element. If a user clicks on one of the links it places the template in each view. While I want to target the view that's inside the content wrapper that the user clicked on.
Instead of nested views you can use directive here as you have repeating same objects so nested views do not help you that much...
just define a directive which is only for templating (of course you can extend its feature by your needs)..,
app.directive('contentTemplate', function() {
return {
restrict: 'E',
template: '<div class="content-view">{{vm.movie.title || "No Movie"}} is selected</div>',
scope: {
movie: '='
},
controller: ContentTemplateController,
controllerAs: 'vm',
bindToController: true
}
})
function ContentTemplateController() {
// your directive controller if you need it
}
then bind your selected content with directive then whenever you change movie content of directive will be changed as well...
<div class="content-wrapper" ng-repeat="movieGroup in movieGroups">
<div class="content" ng-repeat="movie in movieGroup">
<button ng-click="movieGroup.selectedMovie = movie;">{{ movie.title }}</button>
</div>
<content-template movie="movieGroup.selectedMovie"></content-template>
</div>
Creating independent ui-view states with the same name is simply not possible with the current model that ui-router has provided. The closest possible implementation is probably ui-router-extras's sticky module. You can create multiple independent(sticky) states by taking advantage of multiple named views in a state.
DEMO
Javascript
app = angular.module('myApp', [
'ui.router',
'ct.ui.router.extras'
]);
app.controller('mainCtrl', ['$scope',
function($scope){}
])
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: '/'
})
.state('main.sub1', {
sticky: true,
views: {
'sub1#': {
template: 'sub1<ui-view />'
}
}
})
.state('main.sub1.part1', {
template: '.part1'
})
.state('main.sub2', {
sticky: true,
views: {
'sub2#': {
template: 'sub2<ui-view />'
}
}
})
.state('main.sub2.part1', {
template: '.part1'
});
});
HTML
<div class="content-wrapper">
<div class="content">
<a ui-sref="main.sub1">main.sub1</a> |
<a ui-sref="main.sub1.part1">main.sub1.part1</a>
</div>
<div ui-view="sub1">Template goes here</div>
</div>
<div class="content-wrapper">
<div class="content">
<a ui-sref="main.sub2">main.sub2</a> |
<a ui-sref="main.sub2.part1">main.sub2.part1</a>
</div>
<div ui-view="sub2">Template goes here</div>
</div>

Angular UI Bootstrap Modal Dialog Close Event

How do I detect when an Angular UI Bootstrap modal dialog is closed?
I need to know when the dialog closes so I can broadcast a loginCancelled event using the angular-http-auth library to prevent my Angular UI from hanging, especially after closing the modal via clicking on the backdrop.
This works for clicking on the backdrop and pressing the esc key if you are opting in on that.
var modalInstance = $modal.open({
templateUrl: '/app/yourtemplate.html',
controller: ModalInstanceCtrl,
windowClass: 'modal',
keyboard: true,
resolve: {
yourResulst: function () {
return 'foo';
}
}
});
var ModalInstanceCtrl = function ($scope, $modalInstance, yourResulst) {
var constructor = function () {
// init stuff
}
constructor();
$modalInstance.result.then(function () {
// not called... at least for me
}, function () {
// hit's here... clean up or do whatever
});
// VVVV other $scope functions and so on...
};
UPDATE: alternative approach
I have no idea why this way is not documented at http://angular-ui.github.io/bootstrap/ ... but I find it much better. You can now use that page's controller or use a specific controller with the controller as syntax. You could even utilize ng-include for the content of the modal, if you want separation on html. The following works with no JS needed in the controller to setup/configure the modal, as long as you have bootstrap/bootstrapUI included in your project/site
<div class="row">
<button class="btn btn-default" data-toggle="modal" data-target="#exampleModal">Open Example Modal</button>
</div>
<div class="modal fade" id="exampleModal" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">Close</button>
<h2 class="modal-title" id="exampleModalLabel">Modal Example</h2>
</div>
<div class="modal-body" style="padding-bottom:0px;">
<h3>model markup goes here</h3>
</div>
</div>
</div>
</div>
I finished with the following code:
$modal.open(modalOptions).result.finally(function(){
console.log('modal has closed');
});
This way you can avoid the method then()
This worked for me:
var modalInstance = $modal.open({...});
modalInstance.result.then(function () {
//something to do on close
});

Resources