I have a very weird problem and as I can't really copy the actual production code here or at least not much of it, you probably can't help me, but I'll try nevertheless.
Here is a simplified example of what I'm doing:
http://plnkr.co/edit/7IjX4jV9sb2Fb6NpmzUZ?p=preview
angular.module("hello", [
"ui.bootstrap",
"ui.bootstrap.tpls",
]);
angular.module("hello").controller("helloCtrl", function($scope, $modal){
$scope.openModal = function(){
var modalInstance = $modal.open({
templateUrl: 'modal.tpl.html',
controller: 'modalCtrl',
resolve: {
obj1: function(){
return {name:"obj1"};
},
obj2: function(){
return {name:"obj2"};
}
}
});
};
});
angular.module("hello").controller("modalCtrl", function($scope, obj1, obj2){
$scope.obj1 = obj1;
$scope.obj2 = obj2;
})
So I'm opening a modal and resolving the object's to be used in the modal's controller. That example works, but in the real code the obj1 will be resolved to what was supposed to be obj2, and obj2 will be undefined. They are also already wrong when they come to controller, not just after attaching them to scope.
In the real project I'm also using ui-router, but the modal is not it's own state and nothing with those names is resolved in this state or parent states.
If someone has any ideas or wild guesses of what could be causing such behavior, I would really appreciate to hear them.
Edit:
Here are the most relevant parts of the production code:
modal opening controller:
angular.module('cmt').controller('createClusterModalCtrl', function ($scope, $modal, clusterSvc) {
$scope.openCreateClusterModal = function () {
var modalInstance = $modal.open({
templateUrl: '..path to template..',
controller: 'clusterCreateCtrl',
windowClass: 'cmt-xl-modal-window',
resolve: {
initTab: 0,
validationSettings: function(){
//return something simple for debug
return {name:"validation"};
},
cluster: function(){
//return something simple for debug
return {name: "cluster"};
}
}
});
};
});
modal controller:
angular.module('cmt').controller('clusterCreateCtrl', function ($scope, $modalInstance, clusterSvc, toastr, initTab, validationSettings, cluster) {
console.log("validation:");
console.log(validationSettings); //will print name: "cluster"
console.log("cluster:");
console.log(cluster); //will print undefined
......
Found the error:
that resolve "initTab: 0" caused it to get the next defined function and so fort. I had to change it to a function that returns 0.
Would someone care to explain why you can not resolve to something else than a function?
Related
I pass the link of this example, I have a variable called "greeting" that changes its value in a modal window but does not bind. Do not share scope?
http://jsfiddle.net/Bibidesign/Lodkh4jy/7/
var myApp = angular.module('myApp',['ui.bootstrap']);
myApp.controller('GreetingController', ['$scope', '$modal', function($scope,$modal) {
$scope.greeting = 'Hello!';
$scope.changeValues = function() {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
backdrop: 'static',
scope: $scope,
controller: function($scope, $modalInstance) {
$scope.greeting = "Welcome";
$scope.cancel = function(){
modalInstance.close();
}
$scope.ok = function(){
modalInstance.close();
}
}
});
};
}]);
You are partially there. We just need to set up passing the variables between the GreetingController and the Modal controller. We will use the resolve property on the object passed into $modal.open() to pass a value to the modal controller, and than when we close the modal, we will pass back the new value through those the results object. We are also removing scope: $scope, because the controller declaration is overriding that scope copy, and we want to keep these scopes separate. Example to follow.
This answer has a more thorough explanation of what is happening with the resolve, but it is essentially just a simplified way to resolve promises and guarantee data is in the controller before initializing the modal.
myApp.controller('GreetingController', ['$scope', '$modal', function($scope,$modal) {
$scope.greeting = 'Hello!';
// this will handle everything modal
$scope.changeValues = function() {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
backdrop: 'static',
// resolve is an object with all the objects we will pass to the controller
// I'm adding more than just greeting for examples sake
resolve: {
greeting: function () {
return $scope.greeting;
},
testData: function () {
return "This is some random test data";
}
}
// on the controller parameters, we add the properties we are resolving
controller: function($scope, $modalInstance, greeting, testData) {
// the greeting variable passed in through resolve
console.log('greeting', greeting); // expected output: greeting Hello!
// the testData passed in through resolve
console.log('testData', testData); // expected output: testData This is some random test data
// this will be the greeting you are able to access on the modal
// we can set this to the value from the resolve or a new value like below
$scope.greeting = "Welcome";
//$scope.greeting = greeting // this will set the modal to the value passed in from the resolve
// NOTE*** I changed this call to dismiss()
$scope.cancel = function(){
modalInstance.dismiss();
}
$scope.ok = function(){
// what ever we pass in to close will be accessible in the result below
// we are passing in the new greeting - 'Welcome'
modalInstance.close($scope.greeting);
}
}
});
// this is the majority of the new code
modalInstance.result.then(function(okReturnObject){
// this okReturnObject will be whatever you pass in to modalInstance.close()
console.log('return', okReturnObject); // expectedOutput: return Welcome
// this is where we are setting the original value to the new value from the modal
$scope.greeting = okReturnObject;
},function(){
// will be run after modalInstance.dismiss()
console.log("Modal Closed");
});
};
}]);
You can't url refer the text/ng-template as the templateUrl. Instead, add the html form in a separate html file and refer to that in the modal declaration.
Here's a working plunker https://plnkr.co/edit/lMZK0uGNsEmRjAN7teVZ?p=preview
I'm trying to test a certain controller functionality with Jasmine unit testing.
I have a function which opens a modal instance with a new controller:
function openFilterModal(data) {
var modalInstance = $uibModal.open({
controller: FilterModalController,
controllerAs: 'vm',
templateUrl: 'modal.html',
resolve: {
data: function () {
return data;
}
}
});
return modalInstance.result;
}
The controller is defined below:
FilterModalController.$inject = ['alertsModalService', '$uibModalInstance', 'data', '$scope', 'logger', '$timeout'];
function FilterModalController(alertsModalService, $uibModalInstance, data, $scope, logger, $timeout) {
// code goes here }
When I try to call 'openFilterModal', I'm unable to get the controller instance, just getting the promise from it.
I've tried to used the $controller(FilterModalController) function in Jasmine, but it couldn't find the controller.
What is the best practice in that case?
Should I add the controller definition to my module? right now it defined like anonymous controller... not sure if that's good behavior or not.
like that:
app.controller('FilterModalController', FilterModalController);
Is it ok to define 2 controllers on the same module?
Or there is another way to get test the controller?
Thanks!
i need to pass an object to modal controller , i have tried different approach , here is my final code , the object is passed but i get big error in console
Error: [$injector:unpr]
here is my code
vm.openAttendeesModal = function (meeting) {
var modalInstance = $modal.open({
templateUrl: '/App/Main/views/meetings/AttendeesModal.cshtml',
controller: 'attendeeController',
resolve: {
meetingSelected: function () { return meeting }
}
});
}
and here is my modal controller
angular
.module('App')
.controller('attendeeController', attendeeController);
attendeeController.$inject = ['meetingSelected', '$scope', '$modal', 'meetingService'];
function attendeeController(meetingSelected,$scope, $modalInstance, meetingService) {
/* jshint validthis:true */
var vm = this;
vm.meetingSelected = meetingSelected;
and here is complete error
angular.js:12520 Error: [$injector:unpr] http://errors.angularjs.org/1.4.8/$injector/unpr?p0=meetingSelectedProvider%20%3C-%20meetingSelected%20%3C-%20attendeeController
at Error (native)
the funny part is everything is working , even i have access to passed object , but i just feel something is wrong because of that fat error.
any suggestion ?
thanks
try this
var modalInstance = $modal.open({
templateUrl: '/App/Main/views/meetings/AttendeesModal.cshtml',
controller: 'attendeeController as ctrl',
resolve: {
meetingSelected: function () { return meeting }
}
});
or add controllerAs: "ctrl"
Edit:
if you add "attendeeController as ctrl" in AttendeesModal.cshtml remove it.
I'm trying to pass information about a listing that appears on the show page to the modal on that page.
I successfully created the factory service which returns me an object.
angular.module('articles').factory('ProductService', [ '$resource', 'Articles','$stateParams', function($resource, Articles, $stateParams) {
var listingInfo =
Articles.get({
articleId: $stateParams.articleId
});
return listingInfo;
}
]);
(logged by using angular.element(document.body).injector().get('ProductService'))
If I place this in my main ArticlesController I'm able to see the scope via browser console with angular.element($0).scope() and able to access the object by injecting into my controller and giving it a scope of $scope.product = ProductService;, allowing me to access the data in the expected way (product.furtherinfo).
However when trying the same technique for my modal controllers, I'm unable to find the scope when I log through the browser or access the data through binding or brackets.
I've tried passing the value through the resolve, injecting the dependency in all my controllers having to do with my modal, but nothing works.
// Modals
angular.module('articles').controller('ModalDemoCtrl',['$scope', '$modal', '$log', 'ProductService' , function ($scope, $modal, $log, ProductService) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.product = ProductService;
$scope.animationsEnabled = true;
$scope.open = function (size) {
var modalInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
},
product: function () {
return $scope.product;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
$scope.toggleAnimation = function () {
$scope.animationsEnabled = !$scope.animationsEnabled;
};
}]);
The idea is to pass the returned factory object to my modal so I can link it to an input(maybe hidden) that I could designate as a model to send through to an email.
angular.module('articles').controller('ModalInstanceCtrl',['$scope', '$modalInstance', 'items', '$http', 'product','ProductService','$stateParams', function ($scope, $modalInstance, items, $http, product,ProductService,$stateParams) {
$scope.items = items;
$scope.product = product;
$scope.sendMail = function(){
var data = ({
input : this.contactAgentInput,
inputBody : this.contactAgentInputBody,
})
$http.post('/contact-agent', data).
then(function(response) {
// this callback will be called asynchronously
$modalInstance.close($scope.selected.item);
console.log("all is well")
// when the response is available
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
})
}
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}]);
Use a debugger or console.log. If you add console.log(ProductService) in your modal controller, it should show you the service is being injected. – Anid Monsur
Thanks for the suggestion #AnidMonsur i noticed my Rentals controller firing off while In the Sales show page (I split the modules into Sales and Rentals). Thinking that I might be launching the modal from the wrong Module. Investigating now. – Meir Snyder
#AnidMonsur that did it! I was using the same names for some of the modal controllers ( stupid obviously) it must have launched the wrong modal instance and that's why I wasn't able to access the object. After giving them distinct names, it now works. Thanks so much, would have spent another day overlooking the error! – Meir Snyder
Let me guess. You're trying to display the items in the ModalDemoCtrl through the ModalInstanceCtrl, but you can't.
It seems you think DI is going to work as long as you put the name of the dependency but it's not until you register the dependency itself. So 'items' won't ever be a dependency at all and all you get is the value in the inner $scope on the controller (which probrablly is undefined).
In your case I'd say you register a third party factory (which is closer to a singleton) which can be injected just alike ProductService, and eventually would be called ItemsFactory.
Hope it helped.
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.