Im using md-dialog from Material Design and I came across a small issue which causes me a lot of trouble.
I'm using this dialog as a form for creating a new record in db and I need its controller to be loaded from external file. The reason is that I'm using the same dialog in many places of the app (in many other controllers) and I dont want to copy and paste it to each one of them.
I've tried to write it as a service, but the problem is, as I'm binding data from form to the controller I'm using $scope and that way i got "$scope is not defined". When I add $scope as dependencies in that service, I'got injection error.
Do you have any ideas how to load modal controller externally so it will work even with using of $scope?
$scope.showNewContactDialog = function($event) {
var parentEl = angular.element(document.body);
$mdDialog.show({
parent: parentEl,
targetEvent: $event,
templateUrl: 'app/Pages/directory/contacts/newContact.dialog.html',
controller: NewCompanyContactDialogCtrl,
clickOutsideToClose: true,
hasBackdrop: true
});
};
// New User dialog controller
function NewCompanyContactDialogCtrl($scope, $mdDialog) {
var self = this;
$scope.modalIcon = "add";
$scope.modalTitle = 'Nová položka';
$scope.modalAdvanced = true;
// Country Selector
apiCalls.getData(countryUrl, function(response){
$scope.countries = response;
})
// Add New Object
$scope.newItem = function() {
var url = baseUrl + 'new/';
var data = JSON.stringify({
code: $scope.newItem.contactCode,
first_name: $scope.newItem.contactFirstName,
last_name: $scope.newItem.contactLastName,
street: $scope.newItem.contactStreet,
city: $scope.newItem.contactCity,
country: $scope.newItem.contactCountry,
postal: $scope.newItem.contactPostal,
pobox: $scope.newItem.contactPobox,
price_lvl: $scope.newItem.contactPriceLvl,
orgid: $cookies.get('orgid')
});
apiCalls.postData(url, data, function(response){
console.log(response);
// Toast
if(response.status == 201){
$mdToast.show(
$mdToast.simple()
.textContent('Záznam bol vytvorený.')
.position('bottom right')
.action('Skryť')
.highlightAction(true)
.highlightClass('md-warn')
);
$mdDialog.cancel();
}
});
}
To use as service you can do something like:
angular.module('myApp').factory('newCompModal', function($mdDialog){
var parentEl = angular.element(document.body);
function show($event){
return $mdDialog.show({
parent: parentEl,
targetEvent: $event,
templateUrl: 'app/Pages/directory/contacts/newContact.dialog.html',
controller: 'NewCompanyContactDialogCtrl',
clickOutsideToClose: true,
hasBackdrop: true
});
}
return {
show: show
}
});
Then in any controller:
angular.module('myApp').controller('someController',function($scope,newCompModal){
$scope.newCompanyModalShow = newCompModal.show;
})
And pass event in from view
<button ng-click="newCompanyModalShow($event)">New Company</button>
If you need to pass data also from controller to modal you can add another argument and pass it to locals property of $mdDialog or share through another service property
Example of a dialog with external controller:
$mdDialog.show({
scope : scope,
preserveScope : true,
templateUrl : 'template/search.html',
targetEvent : event,
clickOutsideToClose : true,
fullscreen : true,
controller : 'DialogController'
});
And the controller search.js:
(function() {
angular.module('myApp')
.controller('DialogController', DialogController);
DialogController.$inject = ['$scope', '$mdDialog'];
function DialogController($scope, $mdDialog) {
$scope.closeOpenedDialog = closeOpenedDialog;
function closeOpenedDialog() {
$mdDialog.hide();
}
}
})();
If your mdDialog config doesn't recognize your controller name because it belongs to an external file, then instead of doing this:
controller : 'DialogController'
You should load your controller as a directive in your dialog's view:
<md-dialog ng-controller="DialogController">
...
</md-dialog>
Related
I couldn't come up with normal title. Sorry for that.
So the problem is that in a big project, with big business logic there are a lot of modals. And every new modal is the same code with little changes, like templateUrl, controller and such things. This is how pop up is getting called now:
return uibModal.open({
templateUrl: current.path + 'url.html',
controller: 'AppController',
windowClass: 'PopUp',
size: 'md',
resolve: {
disabled: [function () {
return scope.disabled;
}]
}
}).result.then(function( comment ){
record.comment = comment;
})
And this routine never ends. So what I'm interested in is - what is the best practice to reduce the same code(same to this situation) in your project? Should you use service? Or just create global function?
In AngularJS you should always avoid global functions. Services were created for this purpose. I also use $uibModal and was tired of writing the same thing over and over again.
I made a ModalService which allowed me to abstract away a lot of the repetitive code:
function ModalService() {
var ModalService = this;
ModalService.basicModal = function(options) {
var _options = options || {};
return $uibModal.open({
animation: angular.isDefined(_options.animation) ? _options.animation : true,
keyboard: angular.isDefined(_options.keyboard) ? _options.keyboard : true,
backdrop: _options.backdrop || 'static',
size: _options.size || 'sm',
templateUrl: _options.templateUrl || 'templates/modal-message.html', //default template in case user does not provide one
controller: _options.controller || ModalMessageCtrl, // a default controller in case user does not provide one
controllerAs: _options.controllerAs || 'vm',
resolve: options.resolve || {}
});
};
ModalService.simpleModal = function(options) {
...
};
}
You can define many varieties of modals that can be invoked easily from the controller:
ModalService.basicModal();
ModalService.simpleModal();
// etc...
And all of these can accept optional parameters to customize the modal:
ModalService.basicModal({
size: 'lg'
});
ModalService.simpleModal({
templateUrl: "my-custom-template.html",
controller: function($scope) {
//some custom inline controller
}
}).result.then(function() { //do something });
// etc...
You can use $uibModalProvider.options to set the default options during the configuration phase of the application.
app.config(function($uibModalProvider) {
$uibModalProvider.options = {
windowClass: 'PopUp',
size: 'md'
};
});
If you're using UI Bootstrap 2.1.0 or greater you can also leverage angular's component based architecture to remove some of the extra cruft when opening a modal.
Given a component defined as follows:
app.component('myModal', {
bindings: {close: '&', dismiss: '&', resolve: '<'},
controller: MyModalController,
templateUrl: 'myModal.html'
});
You can leverage the component in a modal as follows:
$uibModal.open({
component: 'myModal',
resolve: {
// pass data to component
}
}).result.then(function() {
// Modal closed
}).catch(function() {
// Modal dismissed
});
In my angular project I'm using Angular.js material. And I want to show $mdialog with custom controller, where user changes some data and this data should be applied to my $scope variable. Example what I do now:
function myControllerFn($scope, MyService){
// I do copy of my service variable because I don't want to change it until user will click save button
$scope.name = angular.copy(MyService.name);
$scope.editCurrentProfile = function() {
$scope.showEditProfileDialog($scope.name).then(function(name){
$scope.name = name;
}
}
$scope.showEditProfileDialog = function(name) {
var deferred = $q.defer();
$mdDialog.show({
controller: 'editProfileViewCtrl',
templateUrl: 'controllers/editProfileDialog.tmpl.html',
locals: {
name: name,
deferred: deferred
}
});
return deferred.promise;
};
}
Then in dialog controller I do:
function editProfileViewCtrl($scope, name, deffered) {
deferred.resolve('newName');
}
But I think it is the wrong way. So what is the best way to communicate between two view controllers in angular without new service ? Or better create another service like: EditDialogService, where I will save results ?
When you open a modal, the show() function returns a promise.
$scope.showEditProfileDialog = function(name) {
var modalInstance = $mdDialog.show({
controller: 'editProfileViewCtrl',
templateUrl: 'controllers/editProfileDialog.tmpl.html',
locals: {
name: name
}
});
modalInstance.then(function(result){
// acces what is returned
// In your case, you would do
$scope.name = result;
}, function(error){
// Usually when you cancel your modal
});
}
Your modal controller can be injected with $mdDialog.
function editProfileViewCtrl($scope, name, $mdDialog) {
$scope.close = function() {
$mdDialog.hide('newName');
}
}
You should create a directive with your user as scope variable. Angular in itself is handling the data binding.
It is possible to create a minimal controller function that has access to $scope.
$mdDialog.show({
controller: function () { this.parent = $scope; },
templateUrl: 'controllers/editProfileDialog.tmpl.html',
locals: {
name: name,
deferred: deferred
}
});
Here the Sample Link
I tried to Implement Modal window. I find some sample from online and I Implemented.
Here I Added the Sample file for modal window. which is working fine.
what I exactly need is while open the model window I will call this function.
$scope.callType = {};
$scope.dataFormDialog = function (id) {
$scope.callType.id = id;
exDialog.openPrime({
scope: $scope,
template: '_Product.html',
controller: 'productController',
width: '450px',
//animation: false,
//grayBackground: false
});
};
Here I Am calling _Product.html and productController from sampleController.
Modal window Invoking from sampleController that time.
How to pass the $scope value of sampleController to productController?
Can any one help me on this?...
try this
$scope.dataFormDialog = function (id) {
$scope.callType.id = id;
exDialog.openPrime({
template: '_Product.html',
controller: 'productController',
width: '450px',
resolve: {
Scopevariable: function () {
return $scope;
}
//animation: false,
//grayBackground: false
});
};
app.controller('productController', ["Scopevariable",
function (Scopevariable)
{
// use Scopevariable
}]);
To pass a scope to controller of ng-dialog there is property scope you can assign it with any object and that object and its properties you can use in dialog's controller.
Example -
$scope.value = true;
ngDialog.open({
template: 'externalTemplate.html',
className: 'ngdialog-theme-plain',
scope: $scope
});
<script type="text/ng-template" id="externalTemplate.html">
<p>External scope: <code>{{value}}</code></p>
</script>
In above example you have a value object in $scope. In dialog passing the whole $scope so can access all properties of $scope in externalTemplate.html.
For details check these ng-dialog scope
I have an application that allows the user to create and edit records in a modal Angular Material Design Dialog ($mdDialog)
My problem is to put the object returned by the dialog into a collecion that is in the main controller. Is there a way to do that?
angular.module("module").controller("mainController", function ($scope, $mdDialog) {
$scope.Users = [];
function OpenEditWindow(userToEdit) {
$mdDialog.show({
templateUrl: 'Views/user.html',
controller: 'UserDialogController',
clickOutsideToClose: true,
locals: { // Envia valores para o controller do dialog
User: userToEdit
}
}).then(function (data) {
// Put the object edited into the collection on main controller, to show on the screen
$scope.Users.push(data); // ******** NOT WORKS
});
}
});
angular.module('module')
.controller('UserDialogController', function ($scope, $mdDialog, User) {
$scope.User = User;
$scope.Save = function () {
$mdDialog.hide($scope.User);
}
});
Maybe you can centralize your data and create a service model that persists the state of your user across your application. Such a service can be passed into your controller like every other dependency.
angular.module('module')
.controller('UserDialogController', function ($scope, $mdDialog, User, UserModel) {
$scope.User = User;
$scope.Save = function () {
$mdDialog.hide($scope.User);
}
});
angular.module('module').factory('UserModel', function () {
var userModel = this;
userModel.set = function(){
...
}
return userModel;
});
Given that services are singletons you are guaranteed to have access to the latest and greatest information every time.
Try using a style guide which will greatly improve your code, logic and overall quality. Such a guide could be John Papa's Angular Style Guide
What is returned from $mdDialog.show is a promise. You are putting your then in the wrong place. This is shown in the angular material docs here
angular.module("module").controller("mainController", function ($scope, $mdDialog) {
$scope.Users = [];
function OpenEditWindow(userToEdit) {
var promise = $mdDialog.show({
templateUrl: 'Views/user.html',
controller: 'UserDialogController',
clickOutsideToClose: true,
locals: { // Envia valores para o controller do dialog
User: userToEdit
}
});
promise.then(function (data) {
// Put the object edited into the collection on main controller, to show on the screen
$scope.Users.push(data); // ******** NOT WORKS
});
}
});
I'm trying to implement an AngularJS Modal.
This is my call for the modal
<button data-ng-disabled="!caixa.ativo" data-ng-click="abrir(caixa.id)" class="btn btn-primary btn-xs">Alterar</button>
This is my function
$scope.abrir = function(caixaId) {
var modalInstance = $modal.open({
templateUrl: 'add_modal',
controller: $scope.model,
resolve: {
id: function() {
return caixaId;
}
}
});
};
$scope.model = function($scope, $modalInstance) {
$scope.alerts = [];
//if I remove this code, the modal opens correctly
if (angular.isDefined(id))
alert('edit');
};
But when I click the button, I get this error
Error: id is not defined
$scope.model#http://localhost:8080/websys/resources/js/CaixaController.js:38:1
invoke#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:4182:14
instantiate#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:4190:27
$ControllerProvider/this.$get</<#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:8449:18
resolveSuccess#http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js:1710:32
processQueue#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:13170:27
scheduleProcessQueue/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:13186:27
$RootScopeProvider/this.$get</Scope.prototype.$eval#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:14383:16
$RootScopeProvider/this.$get</Scope.prototype.$digest#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:14199:15
$RootScopeProvider/this.$get</Scope.prototype.$apply#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:14488:13
ngEventHandler/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.js:22954:17
m.event.dispatch#http://code.jquery.com/jquery-latest.min.js:3:8384
m.event.add/r.handle#http://code.jquery.com/jquery-latest.min.js:3:5122
The reason your ID is not defined is you are not injecting id as a dependency to your controller.
$scope.abrir = function(caixaId) {
var modalInstance = $modal.open({
templateUrl: 'add_modal',
controller: modalController,
resolve: {
// adding id as a property here allows you to inject it
// into the controller defined below
id: function() {
return caixaId;
}
}
});
};
// you don't need to bind this controller to your scope
// you don't need to inject $modalInstance as a dependency here,
// but you do need to inject id
function modalController($scope, id) {
$scope.alerts = [];
// now id should be defined since you added it as a dependency
if (angular.isDefined(id))
alert('edit');
};