I would like to call dialog's controller function on $modal.rendered event, is this doable without polluting $scope?
Here is a sample Plunkr:
http://plnkr.co/edit/HzFe65RY3hNme8QuUWaJ?p=preview
So, in promise:
modalDialog.rendered.then(function () {
demo.message = 'Dialog opened';
});
I would like to call onLoaded function from modalController controller.
Thank you, best regards,
You can use a factory/service to share data & functions across controllers;
angular.module('app', ['ui.bootstrap'])
.controller('demoController',['$modal', 'modalService', function($modal, service) {
var demo = this;
demo.message = 'It works!'
demo.modal = function() {
var modalDialog = $modal.open({
controller: 'modalController',
controllerAs: 'modal',
templateUrl: 'modal.html'
});
modalDialog.rendered.then(function () {
demo.message = 'Dialog opened';
service.onLoaded();
});
};
}])
.controller('modalController', ['$modalInstance', 'modalService', function($modalInstance, service) {
var modal = this;
service.modalText = 'Modal Text';
modal.shared = service;
modal.cancel = function() {
$modalInstance.dismiss();
}
}])
.factory('modalService', function() {
var service = {
modalText: 'Modal text',
onLoaded: onLoaded
};
return service;
function onLoaded() {
service.modalText = 'Modal loaded';
}
})
And the following update to the html;
<div class="modal-body">
<pre>{{ modal.shared.modalText }}</pre>
</div>
Updated plunker: http://plnkr.co/edit/q704IjkHSAYwuCfLuYnU?p=preview
Related
I'm trying to open a modal using angular material and inject the scope of the parent, where my data is.
I am attempting to loosely follow the custom/advanced example here:
https://material.angularjs.org/latest/demo/dialog
I do not need the dialog to do anything once closed, so I've eliminated the Dialogcontroller, which seems to only handle 'cancel' and 'answer' upon close. (correct me if I'm wrong here)
The ultimate goal here is to have access to survey in the modal, which is an object in the scope of the parent.
My parent HTML has the review button:
<input type="button" value="Review" ng-click="vm.openReview($event)" />
which triggers the function:
(function () {
appModule
// parent controller
.controller('tenant.views.surveys.index', [
'$scope', 'abp.services.app.survey', '$filter', '$mdDialog',
function ($scope, surveyService, $filter, $mdDialog) {
var vm = this;
vm.openReview = function (ev) {
$mdDialog.show({
//controller: DialogController,// not needed
templateUrl: "/App/tenant/views/surveys/review_modal.html",
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: true,
fullscreen: true
})
//.then(function (answer) {// not needed
// vm.modalStatus = 'You said the information was "' + answer + '".';
//}, function () {
// vm.modalStatus = 'You cancelled the dialog.';
//});
};
// not needed
//function DialogController($scope, $mdDialog) {
// $scope.hide = function() { $mdDialog.hide(); };
// $scope.cancel = function() { $mdDialog.cancel(); };
// $scope.answer = function(answer) { $mdDialog.hide(answer); };
//}
}
])
.
// then the modal controller
.controller('tenant.views.surveys.review', [
'$scope', 'abp.services.app.survey',
function ($scope, surveyService) {
var vmModal = this;
}
]);
})();
Now, in my modal, I have some content:
<div ng-controller="tenant.views.surveys.review as vmModal" class="md-padding dialogdemoBasicUsage" id="popupContainer" ng-cloak="">
<div ng-controller="tenant.views.surveys.review" class="md-padding dialogdemoBasicUsage" id="popupContainer" ng-cloak="">
<md-dialog aria-label="Mango (Fruit)">
<form ng-cloak>
{{vmModal.survey}}
</form>
</md-dialog>
</div>
But I think I'm missing a piece. I don't think vmModal actually contains the scope of the parent. I want access to vmModal.survey.
Do I need to / can I inject the scope directly into the modal controller?
when i try to invoke openDialog function form view i get the following error
ngDialog.open is not a function
here is my code
(function () {
'use strict';
angular
.module('app.user')
.controller('userController', Controller);
Controller.$inject = ['$rootScope', '$log', 'ngDialog', 'tpl','DataService'];
function Controller($rootScope, $log,ngDialog,tpl, DataService) {
var vm = this;
vm.user = {};
vm.createUser = function() {
DataService.createUser(user);
}
vm.openDialog = function() {
$log.log('vm.openDialog is running')
ngDialog.open({
template: 'createUser',
className: 'ngdialog-theme-default'
})
}
activate();
function activate() {
}
}
})();
so what might be problem?
thank you .
See fully working demo over here.
You forgot to add .module('app.user',['ngDialog'])
ngDialog.open(
{
template: 'createUser',
className: 'ngdialog-theme-default'
});
http://plnkr.co/edit/dpbE6lgQDxJYZYOXqU6j?p=preview
Try this
function Controller($rootScope, $log, ngDialog ,tpl, DataService) {
var vm = this;
vm.user = {};
vm.createUser = function() {
DataService.createUser(user);
}
ngDialog.open = function() {
$log.log('vm.openDialog is running')
ngDialog.open({
template: 'createUser',
className: 'ngdialog-theme-default'
})
}
activate();
I think I'm missing something but cannot figure what.
Basically I'm trying to pass an object to the modal like below, but instead of getting the passed object I gets null...so I think is a problem with the scope but I'm new in Angular and need some help.
Controller
app.controller("musicViewModel", function ($scope, $http, $location, $uibModal, $log) {
$scope.selected = null;
$scope.open = function (item) {
$scope.selected = item;
$log.info('Open' + $scope.selected); // get right passes object
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
controller: 'musicViewModel',
size: 'lg',
resolve: {
items: function () {
return $scope.selected;
}
}
});
};
$scope.toggleAnimation = function () {
$scope.animationsEnabled = !$scope.animationsEnabled;
};
});
View
<div class="row" ng-controller="musicViewModel">
<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">
<ul>
<li>
{{ selected }} // always gets null
</li>
</ul>
</div>
</script>
</div>
I'd suggest you to pass the scope of your own controller instead of passing same controller again, by doing that you can remove the resolve also.
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
scope: $scope, //passed current scope to the modal
size: 'lg'
});
Otherwise you need to create a new controller and assign that controller for modal while opening it.
When you use resolve, the map is injected into the given controller.
I recommend that u use a different controller to handle the modal functionality (separation of concerns).
I also recommend to use dependency injection to support minification of the code. Step 5 on the Angular tutorial wil explain this.
A simplified example of the modal controller would be.
(function () {
'use strict';
var app = angular.module('App');
app.controller('musicDetailController',
['$scope', '$uibModalInstance', 'items',
function ($scope, $uibModalInstance, items) {
$scope.items = items;
}]);
}());
You cannot pass an object directly.
I've tried all the solutions above, but wasn't really satisfied. I've solved the issue by writing a simple parser that enables you to pass both strings and objects directly to the modal, through the provided resolve function.
app.controller('ModalController', ['$uibModal', '$scope', function ($uibModal, $scope) {
// Initialize $modal
var $modal = this;
// Open component modal
$modal.open = function (component, size, data) {
// Init modal
var modalInstance = $uibModal.open({
ariaLabelledBy: 'modal-title',
ariaDescribedBy: 'modal-body',
component: component,
size: size || 'md',
resolve: parseResolve(data)
});
};
// Parse the resolve object
function parseResolve(data) {
if (typeof data === 'string') {
return {
data: function() {
return data;
}
}
}
else if (typeof data === 'object') {
var resolve = {};
angular.forEach(data, function(value, key) {
resolve[key] = function() {
return value;
}
})
return resolve;
}
}
}]);
When usings strings
Template:
<button ng-click="$modal.open('modalSomething', 'md', 'value'">
Click
</button>
Component:
bindings: {
resolve: '#'
}
When using objects
Template:
<button ng-click="$modal.open('modalSomething', 'md', {key1: value1, key2: value2})">
Click
</button>
Component:
bindings: {
resolve: '<'
}
I got the below code working:
this.OpenModal = function() {
var modalInstance = $uibModal.open({
url: "/name?parameter=" + $scope.Object.ParamValue,
templateUrl: 'views/module/page.html',
controller: myController
});
}
I have this code inside a controller. I'm using it to open an angularJS Bootstrap modal with another controller attached.
Is there a way I can not use $scope for the ok() and cancel() functions here?
$scope.deleteTest = (test: ITest) => {
var self = this;
var modalInstance = $modal.open({
templateUrl: '/app/tests/partials/deleteTest.html',
controller: ['$scope', '$modalInstance', 'testService',
function ($scope, $modalInstance, testService: ITestService) {
$scope.ok = () => {
var self = this;
testService.deleteTest()
.then(
() => {
$modalInstance.close();
});
};
$scope.cancel = () => {
$modalInstance.dismiss('cancel');
};
}],
});
}
Looks like you are using TypeScript so you can do something like this
var modalInstance = $modal.open({
templateUrl: '/app/tests/partials/deleteTest.html',
controller: DeleteTest,
controllerAs: 'ctrl'
});
//...
class DeleteTest {
static $inject = ['$modalInstance', 'testService'];
constructor(private $modalInstance, private testService: ITestService) {
}
ok() {
this.testService.deleteTest().then(() => this.$modalInstance.close());
}
cancel() {
this.$modalInstance.dismiss('cancel');
}
}
In deleteTest.html you could call the ok() method with something like
<button ng-click="ctrl.ok()">Ok</button>
I have a little issue by using a customize directive within the template field of UI-Bootstrap modal directive.
My aim is send data to modal via resolve attribute and re-use these resolved parameters inside the controller of my own directive.
var app = angular.module('app', ['ui.bootstrap']);
app.controller('MyCtrl', ['$scope', '$modal', function($scope, $modal) {
$scope.openModal = function () {
var popup = $modal.open({
template: '<my-modal></my-modal>',
resolve : {
mydata : function() {
return 42;
}
}
});
};
}]);
app.controller('ModalController', ['$scope', 'mydata', function($scope, mydata) {
//The error is in this directive controller
$scope.mydata = mydata;
}]);
app.directive('myModal', function() {
return {
restrict: 'E',
templateUrl : 'mymodal.html',
controller : 'ModalController',
replace: true
};
});
Maybe I proceed in the wrong way.
Any suggest to make this code functionnal ?
http://plnkr.co/edit/RND2Jju79aOFlfQGnGN8?p=preview
The resolve parameters are only injected to the controller defined in the $modal.open config parameters, but you want to inject it to the directive controller. That will not work. Imagine you would use the myModal directive somewhere else, there wouldn't be a myData object that could be used.
But i don't realy see, what you need the directive for. You could go much easier this way:
app.controller('MyCtrl', ['$scope', '$modal',
function($scope, $modal) {
$scope.openModal = function() {
var popup = $modal.open({
templateUrl: 'mymodal.html',
controller: 'ModalController',
resolve: {
mydata: function() {
return 42;
}
}
});
};
}
]);
// Here the mydata of your resolves will be injected!
app.controller('ModalController', ['$scope', 'mydata',
function($scope, mydata) {
$scope.mydata = mydata
}
]);
Plunker: http://plnkr.co/edit/bIhiwRjkUFb4oUy9Wn8w?p=preview
you need to provide an Object "mydata". Ensure, that you have a correct implemented factory which provides your myData Object. If you had done that, you can "inject" your myData Object where ever you want to.
yourApp.MyDataFactory = function () {
var myData = {i: "am", an: "object"};
return myData;
}
this would provide an "myData" Object
I'm not sure what you are trying to accomplish with the directive, but if you are trying to provide a generic way to invoke the $model, that you can then use from many places in your app, you may be better off to wrap $model with a service. Than you can then call from other places in your app.
I forked and modified your plunkr to work this way: http://plnkr.co/edit/0CShbYNNWNC9SiuLDVw3?p=preview
app.controller('MyCtrl', ['$scope', 'modalSvc', function($scope, modalSvc) {
var mydata = {
value1: 42
};
$scope.openModal = function () {
modalSvc.open(mydata);
};
}]);
app.factory('modalSvc', ['$modal', function ($modal) {
var open = function (mydata) {
var modalInstance,
modalConfig = {
controller: 'ModalController',
resolve: {
mydata: function () {
return mydata;
}
},
templateUrl: 'mymodal.html'
};
modalInstance = $modal.open(modalConfig);
return modalInstance;
};
return {
open: open
};
}]);
Also, I changed mydata to be an object, rather than '42', as I am sure you will have other data to pass in. the markup was updated accouringly:
<div class="modal-body">
BODY {{mydata.value1}}
</div>
Doing it this way, the resolve property works, and you can get your data.
As for the other answers mentioning you must define mydata, the resolve property passed into $model does this for you, so it can be injected into the modal's controller (ModalController), like you have done.