Best way to create a reusable modal window in angularjs - angularjs

I am using html5, angularjs, bootstrap. So each one of them gives many options to create a modal window. Whole of my website has 2 things, one is confirmation dialog or form dialog. So which is the best reusable approach. Should i use html5 or create a directive ?

As mentioned in the comments ui-bootstrap Modal is very useful.
Just for an example here is a factory for confirm modal that you can extend according to your use case:
yourApp.factory("dialog", ["$modal",
function($modal) {
var dialogService = {
confirm: function(options) {
var modalInstance = $modal.open({
templateUrl: 'partials/confirm-modal.html',
controller: ['$scope',
function($scope) {
$scope.header = options.header;
$scope.body = options.body;
$scope.confirmText = options.confirmText || "Close";
$scope.cancelText = options.cancelText || "Confirm";
$scope.hideCancelButton = options.hideCancelButton;
$scope.cancel = function() {
modalInstance.dismiss('cancel');
};
$scope.confirm = function() {
modalInstance.close();
};
}
]
});
return modalInstance.result;
}
}
}
])
And here is your template:
<div class="modal-header">
<button type="button" data-dismiss="modal" aria-hidden="true" class="btn close" ng-click="cancel()">×</button>
<h4 id="noteLabel" class="modal-title">{{header}}</h4>
</div>
<div class="modal-body">
<p ng-bind-html="body" style="font-size: 16px"></p>
</div>
<div class="modal-footer">
<button ng-show="!hideCancelButton" class="btn btn-default" ng-click="cancel()">{{cancelText}}</button>
<button ng-click="confirm()" class="btn btn-primary">{{confirmText}}</button>
</div>

Related

Is there any way to use $uibModal and $uibModalInstance in a single controller to implement modal popup using angular with typescript?

As I am a newbie in angular with typescript I am facing a issue while implemented angular modal popup. The issue is I have one drop-down on which change I have to open a modal popup and that modal popup will have two buttons "Yes" or "No". For this I have one controller where I have injected a dependency.
export class QuestionnaireController {
static ngControllerName = 'questionnaireController';
static inject = ["$uibModal"];
constructor(private $uibModal: ng.ui.bootstrap.IModalService) {
}
public openModalPopup() {
let options: ng.ui.bootstrap.IModalSettings = {
controller: QuestionnaireController,
controllerAs:'ctrl',
templateUrl: 'app/views/Dialogbox.html',
};
this.$uibModal.open(options);
}
}
Most of my code is written in 'QuestionnaireController' and the popup is getting open using this controller but I also want to close this popup so I read a article where it was written that I have to created a new controller "ModalController " to make popup close.
export class ModalController {
static inject = ["$uibModalInstance"];
constructor(private $uibModalInstance: ng.ui.bootstrap.IModalServiceInstance) {
}
public close() {
this.$uibModalInstance.close();
}
}
Popup code is here...
<div ng-app="" id="dvModal">
<div class="modal-header">
</div>
<div class="modal-body">
<p> Evaluated result will be discarded if you continue. Are you sure you want to continue?</p>
</div>
<div class="modal-footer">
<input id="yesBtn" type="button" class="btn btn-default" ng-click="ctrl.Yes('true')" value="Yes" />
<input id="npBtn" type="button" class="btn btn-default" ng-click="ctrl.close()" value="No" />
</div>
and to close this passed Controller : ModalController in options which makes my popup closed on click of "No". But now the issue is generated here, how I again went to "QuestionnaireController" to do "Yes" functionality as "Yes" functionality is written in QuestionnaireController.
Yes, you can!
$uibModal is super flexible tool.
I'm not super familiar with Typescript, but here's my JS solution:
angular
.module('appName', ['ui.bootstrap'])
.controller('SomePageController', ['$scope', '$uibModal', '$log',
function ($scope, $uibModal, $log) {
First you want to do, is to change your openModalPopup() method:
// Instantiate the modal window
var modalPopup = function () {
return $scope.modalInstance = $uibModal.open({
templateUrl: 'blocks/modal/dialog.html',
scope: $scope
});
};
// Modal window popup trigger
$scope.openModalPopup = function () {
modalPopup().result
.then(function (data) {
$scope.handleSuccess(data);
})
.then(null, function (reason) {
$scope.handleDismiss(reason);
});
};
// Close the modal if Yes button click
$scope.yes = function () {
$scope.modalInstance.close('Yes Button Clicked')
};
// Dismiss the modal if No button click
$scope.no = function () {
$scope.modalInstance.dismiss('No Button Clicked')
};
// Log Success message
$scope.handleSuccess = function (data) {
$log.info('Modal closed: ' + data);
};
// Log Dismiss message
$scope.handleDismiss = function (reason) {
$log.info('Modal dismissed: ' + reason);
}
}
]);
Second - modal window HTML template will look like this:
<script type="text/ng-template" id="blocks/modal/dialog.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
Modal content
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="yes()">Yes</button>
<button class="btn btn-warning" type="button" ng-click="no()">No</button>
</div>
</script>
Third - pretty simple SomePage HTML (in your case - Questionnaire) View example :
<div ng-controller="SomePageController">
<button type="button" class="btn btn-default" ng-click="openModalPopup()">Open modal</button>
</div>
All together:
angular
.module('appName', ['ui.bootstrap'])
.controller('SomePageController', ['$scope', '$uibModal', '$log',
function($scope, $uibModal, $log) {
$scope.modalPopup = function() {
modal = $uibModal.open({
templateUrl: 'blocks/modal/dialog.html',
scope: $scope
});
$scope.modalInstance = modal;
return modal.result
};
$scope.modalPopupTrigger = function() {
$scope.modalPopup()
.then(function(data) {
$scope.handleSuccess(data);
},function(reason) {
$scope.handleDismiss(reason);
});
};
$scope.yes = function() {
$scope.modalInstance.close('Yes Button Clicked')
};
$scope.no = function() {
$scope.modalInstance.dismiss('No Button Clicked')
};
$scope.handleSuccess = function(data) {
$log.info('Modal closed: ' + data);
};
$scope.handleDismiss = function(reason) {
$log.info('Modal dismissed: ' + reason);
}
}
]);
<!DOCTYPE html>
<html>
<head>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body ng-app="appName">
<div ng-controller="SomePageController">
<script type="text/ng-template" id="blocks/modal/dialog.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
Modal content
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="yes()">Yes</button>
<button class="btn btn-warning" type="button" ng-click="no()">No</button>
</div>
</script>
<button type="button" class="btn btn-default" ng-click="modalPopupTrigger()">Open modal</button>
</div>
<script src="https://code.angularjs.org/1.5.7/angular.min.js"></script>
<script src="https://code.angularjs.org/1.5.7/angular-animate.min.js"></script>
<script src="https://raw.githubusercontent.com/angular-ui/bootstrap-bower/master/ui-bootstrap-tpls.min.js"></script>
</body>
</html>
Well, if you are that lazy guy like me, the following will also work ;)
var objects = [{
name: "obj1",
value: 1
}, {
name: "obj2",
value: 2
}];
// Generating the modal html
var html = "<div class='modal-header'><h4 class='modal-title'>Select Object</h4></div>";
html += "<div class='modal-body'>";
html += "<select class='form-control' ng-model='selection'>";
for (var i = 0; i < objects.length; i++) {
var ob = objects[i];
html += "<option value='" + ob.value + "'>" + ob.name + "</option>";
}
html += "</select>";
html += "</div>";
html += "<div class='modal-footer'>";
html += '<button type="button" ng-click="dismissModal()" class="btn btn-default" >Close</button>';
html += '<button type="button" ng-click="closeModal()" class="btn btn-primary">Select</button>';
html += "</div>";
// Showing the modal
var objectSelectionModal = $uibModal.open({
template: html,
controller: function($scope) {
// The function that is called for modal closing (positive button)
$scope.closeModal = function() {
//Closing the model with result
objectSelectionModal.close($scope.selection);
};
//The function that is called for modal dismissal(negative button)
$scope.dismissModal = function() {
objectSelectionModal.dismiss();
};
}
});
//Processing the Result
objectSelectionModal.result.then(function(selected) {
alert(selected);
});

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.

AngularJS OpenLayers directive - does not work within angular-ui-dialog

I would like to use AngularJS OpenLayers directive on my page - it works OK but when I put this directive into angular-ui-dialog it won't work.
I cannot see any error in console, any ideas what can be causing this?
Sample usage:
<openlayers width="100px" height="100px"></openlayers>
Plnkr with a demo:
http://plnkr.co/edit/YSfcKaTmNsSpkvSI6wt7?p=preview
It's some kind of a refreshing/rendering issue. You can go around it by adding map to DOM after modal is rendered.
HTML template
<button class="btn btn-primary"
ng-click="demo.modal()">
Open modal
</button>
<script type="text/ng-template"
id="modal.html">
<div class="modal-header">
<h3 class="modal-title">Modal window</h3>
</div>
<div class="modal-body">
<openlayers width="100px"
height="100px"
ng-if="modal.rendered"> <!-- ng-if adds/removes DOM elements -->
</openlayers>
</div>
<div class="modal-footer">
<button class="btn btn-default"
ng-click="$dismiss()">
Cancel
</button>
</div>
</script>
JavaScript
angular.module('app', ['ui.bootstrap', 'openlayers-directive'])
.controller('demoController', function($q, $modal) {
var demo = this;
demo.modal = function() {
$modal.open({
controller: 'modalController',
controllerAs: 'modal',
templateUrl: 'modal.html'
});
};
})
.controller('modalController', function($modalInstance, $timeout) {
var modal = this;
modal.rendered = false;
$modalInstance.rendered.then(function() { // magic here
$timeout(function() {
modal.rendered = true;
});
});
});

Angular data from controller into modal

I have a controller that looks as following:
var ModalDemoCtrl = function ($scope, $modal, $log) {
$scope.items = [{name:'Category1', children:['SPCH-1311','SPCH-1315','SPCH-1321','ARAB-1311','ARAB-1312',
'CHIN-1312','CHIN-1411','CHIN-1412','CZEC-1311','CZEC-1312',
'FREN-1311','FREN-1312','FREN-1411','GERM-1311','GERM-1312',
'GERM-1411','GREE-1412','ITAL-1412','JAPN-1412','KORE-1412',
'LATI-1412','PORT-1412','RUSS-1412','SGNL-1301','SGNL-1302',
'SPAN-1311','SPAN-1312','SPAN-1411','SPAN-1412','VIET-1311',
'VIET-1312','VIET-1411','VIET-1412']},
{name:'Category2', children:['SPCH-1311','SPCH-1315','SPCH-1321','ARAB-1311','ARAB-1312',
'CHIN-1312','CHIN-1411','CHIN-1412','SPAN-1311','SPAN-1312','SPAN-1411','SPAN-1412','VIET-1311',
'VIET-1312','VIET-1411','VIET-1412']}];
$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());
});
};
};
and my modal looks like the following:
<a class="btn btn-default pull-right" data-toggle="modal" data-target="#myModal">Add Course <span class="glyphicon glyphicon-plus"></span></a>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">{{subcategory.name2}}</h4>
</div>
<div class="modal-body" align="center">
<font size="2" align="center">Required Credits : <span class="badge badge-machb">{{subcategory.required2}} </span>
Completed Credits : <span class="badge badge-machb">{{subcategory.completed2}} </span>
Planned Credits : <span class="badge badge-machb">{{subcategory.planned2}} </span></font>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
The question is how do i define buttons in such a way that it display it displays the children of the contents of "Category1" when a button named "category1" is clicked ina a modal and "Category2" when the corresponding is clicked?
The planned, required and completed credits in the above modal are from another controller and hence it can be neglected!
The answer is quite straightforward. See plunker to get a complete view of my discussion below.
Iterate the items via ng-repeat and display each item.category as a button which is bound by an ng-click event and pass the index of the item to be used for the modal to resolve.
HTML
<body ng-controller="ModalDemoCtrl">
<button ng-repeat="item in items" ng-bind="item.name" ng-click="open($index)"></button>
</body>
The html fragment above suggests that the ng-click event callback open() must accept the current $index of the iterated items. Use the $index to get the specific category and pass it to the modal's controller ModalInstanceCtrl $scope to be used by the myModalContent.html template.
JAVASCRIPT
var ModalDemoCtrl = function ($scope, $modal, $log) {
$scope.items = [{name:'Category1', children:['SPCH-1311','SPCH-1315','SPCH-1321','ARAB-1311','ARAB-1312',
'CHIN-1312','CHIN-1411','CHIN-1412','CZEC-1311','CZEC-1312',
'FREN-1311','FREN-1312','FREN-1411','GERM-1311','GERM-1312',
'GERM-1411','GREE-1412','ITAL-1412','JAPN-1412','KORE-1412',
'LATI-1412','PORT-1412','RUSS-1412','SGNL-1301','SGNL-1302',
'SPAN-1311','SPAN-1312','SPAN-1411','SPAN-1412','VIET-1311',
'VIET-1312','VIET-1411','VIET-1412']},
{name:'Category2', children:['SPCH-1311','SPCH-1315','SPCH-1321','ARAB-1311','ARAB-1312',
'CHIN-1312','CHIN-1411','CHIN-1412','SPAN-1311','SPAN-1312','SPAN-1411','SPAN-1412','VIET-1311',
'VIET-1312','VIET-1411','VIET-1412']}];
$scope.open = function ($index) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
item: function() {
return $scope.items[$index];
}
}
});
};
};
var ModalInstanceCtrl = function ($scope, $modalInstance, item) {
$scope.item = item;
};
I'm not sure if this is the answer you're looking for, but here it goes. It seems like you want it so that when you click a button, it will display the children of one of your categories. So, here's the code for that.
HTML to display a button for each category:
<button ng-repeat="item in items" ng-click="displayChildren(item)" ng-bind="item.name"></button>
UL to display the children when you select the button:
<ul>
<li ng-repeat="child in children" ng-bind="child"></li>
</ul>
The code in the controller:
$scope.items = [
{
name: "category1",
children: [
"CHIN-1",
"CHIN-2",
"CHIN-3"
]
},
{
name: "category2",
children : [
"VIET-1",
"VIET-2",
"VIET-3"
]
}];
$scope.displayChildren = function(item){
$scope.children = item.children;
}

Bind values to UI Bootstrap Modal

I have a table with a view button, when view is clicked modal display but now I want to display certain data on the modal. I am using .html pages.
I am not sure what am I missing here
html
<td>
<span>
<input class="btn btn-sm btn-dark" data-ng-click="launch('create',client)" type="button" value="view" />
</span>
</td>
This will luanch the modal
Modal
<div class="modal fade in" ng-controller="dialogServiceTest">
<div class="modal ng-scope">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">
<span class="glyphicon glyphicon-star"></span> Client Details
</h4>
</div><div class="modal-body">
<ng-form name="nameDialog" novalidate="" role="form" class="ng-pristine ng-invalid ng-invalid-required">
<div class="form-group input-group-lg" ng-class="{true: 'has-error'}[nameDialog.username.$dirty && nameDialog.username.$invalid]">
<label class="control-label" for="username">Name:</label>
<input type="text" name="username" id="username" ng-model="client.ClientName" ng-keyup="hitEnter($event)" required="">
<span class="help-block">Enter your full name, first & last.</span>
</div>
<div>{{client.ClientName}}</div>
</ng-form>
</div><div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
<button type="button" class="btn btn-primary" ng-click="save()" ng-disabled="(nameDialog.$dirty && nameDialog.$invalid) || nameDialog.$pristine" disabled="disabled">Save</button>
</div>
</div>
</div>
</div>
Angular
angular.module('modalTest', ['ngRoute','ui.bootstrap', 'dialogs'])
.controller('dialogServiceTest', function ($scope,$http, $rootScope, $timeout, $dialogs) {
$scope.clients = []; //Array of client objetcs
$scope.client = {}; //Single client object
$scope.launch = function (which,client) {
var dlg = null;
alert(client.ClientName);
dlg = $dialogs.create('/templates/Modal.html', 'whatsYourNameCtrl', {}, { key: false, back: 'static' });
dlg.result.then(function () {
$scope.client.ClientName = client.ClientName;
});
})
.run(['$templateCache', function ($templateCache) {
$templateCache.put('/templates/Modal.html');
}]);
here is some of my code
$scope.showScreenSizePicker = function(){
$scope.actionmsg = "";
var modalWindow = $modal.open({
templateUrl: '{{url()}}/modals/modalScreenSizePicker',
controller: 'modalScreenSizePickerController',
resolve: {
titletext: function() {return "Screen Sizes: ";},
oktext: function() {return "Close";},
canceltext: function() {return "Cancel";},
labeltext: function() {return "";},
}});
modalWindow.result.then(function(returnParams) {
$scope.setViewSize(returnParams[0], returnParams[1]);
});
}
you can see i am passing variables into modal using resolve. If you want to pass values back from the modal you can grab the variable returnParms (array)
and here is my controller code:
angular.module('myWebApp').controller('modalScreenSizePickerController', function($scope, $modalInstance, titletext, labeltext, oktext, canceltext) {
$scope.titletext = titletext;
$scope.labeltext = labeltext;
$scope.oktext = oktext;
$scope.canceltext = canceltext;
$scope.customHeight = 800;
$scope.customWidth = 600;
$scope.selectCustomSize = function(width, height){
if (width < 100){ width = 100; }
if (height < 100){ height = 100; }
$scope.selectItem(width, height);
}
$scope.selectItem = function(width, height) {
var returnParams = [width, height];
$modalInstance.close(returnParams);
};
$scope.cancel = function() {
$modalInstance.dismiss();
};
});
hope my sample helps
I think what you are looking for is the resolve property you can use with the $modal service. I am not exactly sure which version of UI Bootstrap you are using, but the latest one works as follows:
var myModal = $modal.open({
templateUrl: '/some/view.html',
controller: 'SomeModalCtrl',
resolve: {
myInjectedObject: function() { return someObject; }
});
myModal.result.then(function(){
// closed
}, function(){
// dismissed
});
Then you can use the injected resolved value inside the modals controller:
app.controller('SomeModalCtrl', function ($scope, $modalInstance, myInjectedObject) {
// use myInjectedObject however you like, eg:
$scope.data = myInjectedObject;
});
You can acces the client in modal by using "$scope.$parent.client" - "$parent" give you $scope from witch the modal was open with all data.

Resources