angularjs $modal avoid multiple instances - angularjs

I want to know it there is a way to avoid opening multiple modal instances, or by some id or some function?
i want to avoid boolean variables to set true or false when i open, because i have a page with a lot of modals and that is not cool.
In my example if you click "Modal 3" buttonand the "Do stuff button" it opens a lot of instances, i have a plunker working example here:
modalInstance = $modal.open({
templateUrl: 'myModalContent2.html',
controller: ModalInstanceCtrl,
scope: $scope
});
http://plnkr.co/edit/fkx9faTdDsDjVpgFVKlo?p=preview

If you just want to refresh the content that's inside the modal, you can simply give your modal-body an id, and set the innerHTML in your otherfunction()
<div id="myModal" class="modal-body">
<h3>MODAL TITLE</h3>
<button ng-click="otherFunction()" class="btn btn-default">Do stuff</button>
</div>
in app.js
$scope.otherFunction = function () {
document.getElementById("myModal").innerHTML = "New content";
}

Related

Trigger bootstrap modal by AngularJs and then get data by $http.post

I have a list of customers each customer have button more info.
I want , when i click on it then showing bootstrap modal by AngularJs controller and then request data by $http.post and getting some more info about this customer and showing info inside modal.
How can i do this purpose ?
this button :
<button type='button' class='btn btn-primary btn-sm'
data-ng-click='moreinfo(customer.id)' >more info</button>
You can first pass each customer info variable to each more info.
Button like this :
<button type='button' class='btn btn-primary btn-sm btnmargin'
data-toggle='modal' data-target='#cInfo' data-ng-click='moreinfo(customer)'
>more info</button>
then you should write this code inside controller :
$scope.customerinfo=[];
$scope.moreinfo= function(customer){
$scope.customerinfo= customer;
};
Html bootstrap modal :
<!-- Modal start -->
<div class='modal fade' id='cinfo' tabindex='-1' role='dialog'
aria-labelledby='myModalLabel' aria-hidden='true'>
<div class='modal-dialog modal-lg' role='document'>
<div class='modal-content'>
<div class='modal-header'>
<button type='button' class='close' data-dismiss='modal'>
<span aria-hidden='true'>×</span>
<span class='sr-only'>Close</span></button>
<h4 class='modal-title text-danger'
id='myModalLabel'>customer info</h4>
</div>
<div class='modal-body'>
{{customerinfo.firstName}}
</div>
<div class='modal-footer'>
<button type='button' class='btn btn-default'
data-dismiss='modal'>close</button>
</div>
</div>
</div>
</div>
<!-- Modal end -->
Now you can click on each row button more info and see info in inside modal body.
Use ngDialog instead of bootstrap modal.
It is easy to implement in angularjs and you can have different controller for it as well and you can definitely transfer data from main page to this ngDialog.
https://github.com/likeastore/ngDialog
I will suggest you to go with ui-bootstrap but looking at other answers and considering you do not want to add any more JS library/plugin
Hope this helps you
Add a directive called bootstrap-modal as following
app.directive('bootstrapModal', ['$rootScope', '$http', function ($rootScope, $http) {
"use strict";
return {
restrict: "A",
//add isolated scope if you want
//scope: {
//},
link: function (scope, element) {
scope.$on('showModal', function (event, object) {
//fire your ajax here
$http.get('url').then(function(response){
//process your response alter DOM and show modal
element.modal('toggle');
});
});
}
};
}]);
and in your moreInfo function in controller
$scope.moreInfo = function(){
$rootScope.$broadCast('showModal', dataToPassToListener)
}
You should use the directive with the div which you want to show as modal. As in the same div where you would have given role="dialog" if you would have used simple bootstrap.js
I know that you don't want more JS plugin but I suggest you to use the UI Bootstrap for Angularjs:
https://angular-ui.github.io/bootstrap/
It's basically a set of pre-defined directives you can use to load Bootstrap component.
In your case, the thing can end like that:
<button type="button" class="btn btn-primary" ng-click = "moreinfo(customer.id)"> More Info </button>
In your controller :
angular.module('myApp').controller('CustomerInfoCtrl',['$uibModalInstance','$scope', function($uibModalInstance,$scope){
$scope.moreinfo = function(id){
var InfoModal = $uibModalInstance.open({
templateUrl : 'route/to/my/template.html,
controller: 'MoreInfoCtrl',
scope: $scope,
resolve: {
customerId : function(){
return id;
}
}
});
InfoModal.result.then(function(){
//callback when modal closed
},function(){
//callback when clicked on cancel to dismiss the modal
});
}]);
Then you create another controller, MoreInfoCtrl:
angular.module('myApp').controller('MoreInfoCtrl',['$http','$scope','id', function($http, $scope, id){
//Do your http call with the variable id (i.e the customer.id )
}]);
You have plenty of options. You can easily pass variables, scope or do callback process.
I'm using it a lot in a project and it really helps a lot.
I suggest you to try it. And it's not really heavy (from above link):
Whichever method you choose the good news that the overall size of a
download is fairly small: 122K minified for all directives with
templates and 98K without (~31kB with gzip compression, with
templates, and 28K gzipped without)

Angular refresh current page - problems

home.html is a template with two fieldsets.
I use ng-show to make the first fieldset visisble when the page loads and when a user clicks a button the other fieldset is made visible and the first one hidden.
This is accomplished by using a variable 'preview' like so (this is a jsfiddle) :
<div ng-app="app">
<div ng-controller="MainController">
<fieldset ng-show="!preview">
<p>This is fieldset 1</p>
<button ng-click="toggleIt()">Toggle</button>
</fieldset>
<fieldset ng-show="preview">
<p>This is fieldset 2</p>
</fieldset>
Home
</div>
</div>
and the controller is like:
angular.module('app', []).
controller('MainController', ['$scope', function ($scope) {
$scope.preview = false;
$scope.toggleIt = function(){
$scope.preview = true;
}
$scope.returnIt = function(){
location.reload();
}
}]);
In JsFiddle it works fine but when I use the 'Home' link in my angular app which is:
Home
and this is picked up by the app.routes.js file
.when('/', {
templateUrl : 'app/views/pages/home.html',
controller: 'MainController',
controllerAs: 'main'
})
Nothing happens - fieldset 2 is still visible rather than fieldset 1.
I was expecting that $scope.preview would be set to false as this is the first line in the controller and that would make the first fieldset visible again.
When I do a browser refresh it works but not using the routing.
I have tried location.reload(); (and this works in the fiddle), but when I apply it inside the app controller I get TypeError: $location.reload is not a function.
I have tried $route.reload() which sends it into an infinite loop, and window.location.reload() which keeps reloading.
Is there a simple way I can achieve a browser-like refresh of the page via the routing?

AngularJS Modal not showing up when templateUrl changes

So far, what I have is straight off the Angular UI example:
Controller:
var ModalDemoCtrl = function ($scope, $modal) {
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl
});
};
};
var ModalInstanceCtrl = function ($scope, $modalInstance) {
$scope.close = function () {
$modalInstance.dismiss('cancel');
};
};
And this section, which is just in sitting in the .html for the whole page this modal is on.
Html:
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
<button class="btn btn-warning" ng-click="close()">X</button>
</div>
<div class="modal-body">
Stuff
</div>
</script>
This works just fine. But I'm trying to refactor some things out and organize my code, so I would like to move the modal html to its own file. When I do so, and try to use it as by changing the templateUrl to the path: \tmpl\myModalContent.html, it doesn't show up. The backdrop still appears and inspecting the page shows that it loaded correctly, but just won't show up.
I've tried changing the css for the modal per these suggestions with no difference.
My question is, why does this work fine if the script tag is in the main html, but not at all if it is in it's own file?
Here is a plnkr that shows what I mean. If you copy what is in the template.html and place it right above the button in the index.html file, it works...
Remove template declaration for template.html and just put raw HTML in there like this:
<!--script type="text/ng-template" id="template.html"-->
<div class="modal-body">
Hello
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="cancel()">OK</button>
</div>
<!--/script-->
Your plnkr worked fine with second click to the button. It'd show the modal as expected. The reason it showed up with second click is because Angular would load up the 'uncompiled' template the first time, then it compiled the template to raw HTML which is ready for your subsequent clicks.
EDIT: Also, when you put the template code right in index.html, Angular compiles the template during its initial pass through the DOM; that's why the modal seemed to work.
Well I am clearly a dummy. All I had to do was include my new file in the main view.
<div ng-include="'path-to-file.html'"></div>
Then calling it from the controller was easy, all I needed was the id (modalContent.html) as the templateUrl.
Just keep swimming, and you'll eventually get there :)

Using AngularJS, how do I set $scope properties in the controller of the parent page

Thanks for looking.
I have the following markup for a modal which shares the same angular controller as it's parent page:
<!-- START Add Event Video -->
<script type="text/ng-template" id="EventVideo.html">
<div class="event-modal">
<div class="modal-header"><h3>Event Video</h3></div>
<div class="modal-body">
<p>Please enter the URL of either a <strong>YouTube</strong> or <strong>Vimeo</strong> video.</p>
<span ng-if="!Event.VideoUrlIsValid" style='color:#9f9f9f;'>This doesn't look like a valid YouTube or Vimeo Url. Your video may not work.</span>
<div class="row" ng-controller="EventCreateController">
<div pr-form-input span="12" name="videoUrl" ng-model="Event.Item.VideoUrl" placeholder="YouTube or Vimeo URL" isRequired="false" no-asterisk></div>
</div>
</div>
<div class="modal-footer"><button class="btn btn-primary" ng-click="Event.UI.EventVideoModal.Close()">Done</button></div>
</div>
</script>
<!-- END Add Event Video -->
And here is the relevant JavaScript:
EventVideoModal: {
Open: function () {
$scope.EventVideoModal = $modal.open({
templateUrl: 'EventVideo.html',
controller: 'EventCreateController',
scope: $scope
});
},
Close: function () {
$scope.EventVideoModal.close();
}
}
Please note the Event.Item.VideoUrl model reference.
The modal allows a user to set the URL of a video, and the goal is to have that set $scope.Event.Item.VideoUrl in the controller and then close the modal. The parent page and the modal both share the same controller, so I had hoped that this would work.
The modal behavior is fine (opens and closes as it should), but the $scope.Event.Item.VideoUrl property is not getting set.
Any advice is appreciated.
Problem Solved!
Thanks to Bogdan Savluk, I realized that I had a scope inheritance problem. So, removing both the explicit reference to the controller in the modal HTML as well as in the JavaScript constructor, resolved my problem:
<!-- START Add Event Video -->
<script type="text/ng-template" id="EventVideo.html">
<div class="event-modal">
<div class="modal-header"><h3>Event Video</h3></div>
<div class="modal-body">
<p>Please enter the URL of either a <strong>YouTube</strong> or <strong>Vimeo</strong> video.</p>
<span ng-if="!Event.VideoUrlIsValid" style='color:#9f9f9f;'>This doesn't look like a valid YouTube or Vimeo Url. Your video may not work.</span>
<!-- <div class="row" ng-controller="EventCreateController"> <--REMOVE THIS! -->
<div class="row">
<div pr-form-input span="12" name="videoUrl" ng-model="Event.Item.VideoUrl" placeholder="YouTube or Vimeo URL" isRequired="false" no-asterisk></div>
</div>
</div>
<div class="modal-footer"><button class="btn btn-primary" ng-click="Event.UI.EventVideoModal.Close()">Done</button></div>
</div>
</script>
<!-- END Add Event Video -->
And here is the relevant JavaScript:
EventVideoModal: {
Open: function () {
$scope.EventVideoModal = $modal.open({
templateUrl: 'EventVideo.html',
//controller: 'EventCreateController', <--REMOVE THIS!!
scope: $scope
});
},
Close: function () {
$scope.EventVideoModal.close();
}
}
If you are passing scope to $modal.open() than scope for modal would be created as child scope from passed scope... - so you will have access to all properties from it.
But in case when you are passing the same controller to it - that controller would be applied to new scope and will override all properties from parent.
So in general, as I see the only thing you need to do to achieve desired result is to remove controller from configuration passed to $modal.open() or replace it with something that is specific only for that modal.

AngularStrap close modal with controller

I'm using AngularStrap with bootstrap.
I have a modal dialog that uses it's own controller. How can I close the modal using this local controller?
I instantiate the controller on a button like this:
<button type="button"
class="btn btn-success btn-lg"
bs-modal="modal"
data-template="user-login-modal.html"
data-container="body"
ng-controller="userLoginController"
>Click here to log in</button>
and the userLoginController has this:
$scope.authenticate = function(){
this.hide(); // this doesn't work
}
This is obviously just a demo, I want it to close on successful login, but this is where the code I'd use to close it would go.
I've tried instantiating the modal programmatically (use the $modal service to create the modal) but I haven't been able to figure out how to inject the controller through that method.
If I were to do something like emit an event from the modal using the bs-modal directive, how can I reference the modal to close it?
here's my plnkr:
http://plnkr.co/edit/m5gT1HiOl1X9poicWIEi?p=preview
When in the on-click function do
$scope.myClickEvent = function () {
this.$hide();
}
Figured out a good method:
I moved the ng-controller to the TEMPLATE and instantiate the modal using the provided modal service. I then use a rootscope broad cast to let everyone know that someone successfully logged in.
new controller code:
var loginModal = $modal({template:'/template.html', show:false});
$scope.showLogin = function(){
loginModal.$promise.then(loginModal.show);
}
$scope.$on("login", function(){
loginModal.$promise.then(loginModal.hide);
});
the button just looks like this now:
<button type="button"
class="btn btn-success btn-lg"
ng-click="showLogin()"
>Click here to log in</button>
and my template has the old ng-controller in the first tag.
I am probably too late, but just wish to share my answer. If all you need is hiding the modal after form success, then bind that $hide function to one of controller varriable.
<div class="modal" data-ng-controller="Controller" data-ng-init="bindHideModalFunction($hide)">
In the controller:
// Bind the hiding modal function to controller and call it when form is success
$scope.hideModal;
$scope.bindHideModalFunction =function(hideModalFunction){
$scope.hideModal = hideModalFunction;
}
I found all of the above answers way too complicated for your use case (and mine when I ran into this problem).
All you need to do, is chain the ng-click to use the built in $hide() function that angular strap bundles.
So your ng-click would look like: ng-click="authenticate();$hide()"
Using Angular and bootstrap if you want to submit data to controller then have the modal close just simply add onclick="$('.modal').modal('hide')" line to the submit button. This way it will hit the controller and close the modal. If you use data-dismiss="modal" in the button submit never hits the controller. At least for me it didn't. And this is not to say my method is a best practice but a quick one liner to get data to at least submit and close out the modal.
<div class="modal fade" id="myModal" ng-controller="SubmitCtrl">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<form ng-submit="submit()">
<input type="text" ng-model="name" />
<button type="submit" onclick="$('.modal').modal('hide')">Submit</button>
</form>
</div>
</div>
</div>
</div>
Perhaps open it with the service on click and have it close itself on the $destroy event?
$scope.openModal = function()
{
$scope.modal = $modal({
template: "user-login-modal.html",
container="body"
});
}
$scope.$on("$destroy", function()
{
if ($scope.modal)
{
$scope.modal.hide();
}
});

Resources