I am having the toughest time figuring out how to get my modal to work.
I have a main application document.
I have my modal code to open a modal with a different document.
When I run the document link by itself it works, but when I try to open it in the modal it doesn't seem to find its controller
angular.js:12314Error: [ng:areq] http://errors.angularjs.org/1.4.1/ng/areq?p0=SimpleCtrl&p1=not[object Object]%function%C%got%undefined
$scope.openPopup2 = function (size, qCode) {
var modalInstance = $uibModal.open({
animation: true,
templateUrl: ('core/media/media.nl?id=11457&c=TSTDRV1365574&h=a2ecbb8c50da60473910&_xt=.html?qcode='
+qCode
+'&productid='
+$scope.siteInformation.productId),
scope: $scope,
controller: SimpleCtrl,
size: size,
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
I have tried to remove "controller: SimpleCtrl,"
and even put it in quotes controller: "SimpleCtrl"
I just get similar errors.
The SimpleCtrl gets referenced from the new document that is supposed to appear.
What am I missing?
Ok, like #Michael Rose's comment I moved it to the main application. I was hoping to just have the page load it itself. I stopped fighting it and put it into the main app and it works now. thanks
Related
I have a grid-view containing many records and I want this behaviour that when the user double-click on each record, a window-like modal dialogue opens for him to view details about that record, and meanwhile he/she can read other records on the grid-view and maybe double click on another record to open a new window to view selected record details while another window is still open.
my question is very similar to this question I found on StackOverflow
but the accepted answer doesn't seem to work.
this is my effortless project to test this workflow,
app.controller('ModalCtrl', function($scope, $modal) {
$scope.showModal = function() {
$scope.opts = {
templateUrl : 'modalContent.html',
controller : ModalInstanceCtrl,
resolve: {}
};
$scope.opts.resolve.item = function() {
}
var modalInstance = $modal.open($scope.opts);
modalInstance.result.then(function(){
},function(){
console.log("Modal Closed");
});
}; })
but it's created by modal and I know modals are not designed for such behaviour and I would like to know the best solution for such thing,
thanks in advance.
I am having no joy with implementing require: {} property as part of an angular component. Allow me to demonstrate with an example I have.
This is the component/directive that supposed to fetch a list of judgements. Nothing very fancy, just a simple factory call.
// judgements.component.js
function JudgementsController(GetJudgements) {
var ctrl = this;
ctrl.Get = function () {
GetJudgements.get().$promise.then(
function (data) {
ctrl.Judgements = data.judgements;
}, function (error) {
// show error message
});
}
ctrl.$onInit = function () {
ctrl.Get();
};
}
angular
.module('App')
//.component('cJudgements', {
// controller: JudgementsController,
//});
.directive('cJudgements', function () {
return {
scope: true,
controller: 'JudgementsController',
//bindToController: true,
};
});
I am trying to implement component require property to give me access to ctrl.Judgements from the above component/directive as follows:
// list.component.js
function ListController(GetList, GetJudgements) {
var ctrl = this;
ctrl.list = [];
ctrl.Get = function () {
GetList.get().$promise.then(
function (data) {
ctrl.list = data.list;
}, function (error) {
// show error message
});
};
//ctrl.GetJudgements = function () {
// GetJudgements.get().$promise.then(
// function (data) {
// ctrl.Judgements = data.judgements;
// }, function (error) {
// // show error message
// });
//}
ctrl.$onInit = function () {
ctrl.Get();
//ctrl.GetJudgements();
};
}
angular
.module('App')
.component('cTheList', {
bindings: {
listid: '<',
},
controller: ListController,
controllerAs: 'ctrl',
require: {
jCtrl: 'cJudgements',
},
template: `
<c-list-item ng-repeat="item in ctrl.list"
item="item"
judgements="ctrl.Judgements"></c-list-item>
<!--
obviously the reference to judgements here needs to change
or even better to be moved into require of cListItem component
-->
`,
});
Nice and simple no magic involved. A keen reader probably noticed GetJudgement service call in the ListController. This is what I am trying to remove from TheList component using require property.
The reason? Is actually simple. I want to stop database being hammered by Judgement requests as much as possible. It's a static list and there is really no need to request it more than once per instance of the app.
So far I have only been successful with receiving the following error message:
Error: $compile:ctreq
Missing Required Controller
Controller 'cJudgements', required by directive 'cTheList', can't be found!
Can anyone see what I am doing wrong?
PS: I am using angular 1.5
PSS: I do not mind which way cJudgement is implemented (directive or component).
PSSS: If someone wonders I have tried using jCtrl: '^cJudgements'.
PSSSS: And multiple ^s for that matter just in case.
Edit
#Kindzoku posted a link to the article that I have read before posting the question. I hope this also helps someone in understanding $onInit and require in Angular 1.5+.
Plunker
Due to popular demand I made a plunker example.
You should use required components in this.$onInit = function(){}
Here is a good article https://toddmotto.com/on-init-require-object-syntax-angular-component/
The $onInit in your case should be written like this:
ctrl.$onInit = function () {
ctrl.jCtrl.Get();
};
#iiminov has the right answer. No parent HTML c-judgements was defined.
Working plunker.
I am trying to write a unit test for an Angular component that opens a dialog, but am unable to do so because I cannot trigger the closing of the dialog.
How can I cause the md dialog to resolve from the test case?
I have created a repository with a basic example where the problem can be reproduced, and copied the central bits below. There is an index.html to manually verify that the code is working, a test case that displays the problem and an example of how the tests are written in the md code.
Repository - https://github.com/gseabrook/md-dialog-test-issue
The component is extremely basic
angular
.module('test', ['ngMaterial'])
.component('dialogTest', {
template: '<button ng-click="showDialog()">Show Dialog</button>',
controller: function($scope, $mdDialog) {
var self = this;
$scope.showDialog = function() {
self.dialogOpen = true;
var confirm = $mdDialog.confirm()
.title('Dialog title')
.ok('OK')
.cancel('Cancel');
$mdDialog.show(confirm).then(function(result) {
self.dialogOpen = false;
}, function() {
self.dialogOpen = false;
});
}
}
});
And the test is also very simple
it("should open then close the dialog", function() {
var controller = element.controller("dialogTest");
expect(controller.dialogOpen).toEqual(undefined);
expect(element.find('button').length).toEqual(1);
element.find('button').triggerHandler('click');
expect(controller.dialogOpen).toBeTruthy();
rootScope.$apply();
material.flushInterimElement();
element.find('button').eq(2).triggerHandler('click');
rootScope.$apply();
material.flushInterimElement();
expect(controller.dialogOpen).toBeFalsy();
});
I managed to resolve the issue by setting the root element as the problem seemed to be related to element being compiled in the test being unconnected with the root element that angular-material appended the dialog too.
I've updated the github repository with the full code, but the important bits are
beforeEach(module(function($provide) {
rootElem = angular.element("<div></div>")
$provide.value('$rootElement', rootElem);
}));
beforeEach(inject(function(_$rootScope_, _$compile_, $mdDialog, _$material_) {
...
element = getCompiledElement();
angular.element(window.document.body).append(rootElem);
angular.element(rootElem).append(element);
}));
So this is is an angularjs app.
I have implemented this angular-scroll api :https://github.com/oblador/angular-scroll, to show a catalog of products, where the content is loaded from db. this catalog has all the subcategories (with its products) and every subcategory has an anchor identified like: anchor+categoryId.
So from the menu , i click a category and it scroll nicely to the correct section.
The problem arise when I need to create some links from other pages of the site, to go to an specific section category inside the catalog. Because I have ng-route, i need to create a new url to redirect to the catalog, and there capture when the content is loaded to do the scroll to the required category.
BUT I have a directive associated with the route of the catalog, that looks for the partials depending on the domain of the client, so to show the correct template i have to use an $http , get the content and replace it in my directive.
Because that I dont know how i can know when the content of the directive is ready to make the call to the scroll... better show some code here :
this is the route that is receiving the call
$routeProvider.
when('/products/category/:categoryId/page/:page/anchor/:anchorId?', {
template:'<product-display-view></product-display-view>',
controller: 'ProductListCtrl',
access: {
authorizedRoles: [USER_ROLES.all]
},
resolve: {
wait : 'waitForIt',
prefetchDataProducts: ['waitForIt','$route','SearchService',
function(waitForIt,$route,SearchService) {
return waitForIt.then(function() {
return SearchService.getProducts($route.current.params.categoryId,$route.current.params.page);
});
}],
prefetchDataCategories:['waitForIt','CategoryService',
function(waitForIt,CategoryService) {
return waitForIt.then(function() {
return CategoryService.getCategories();
});
}]
}
}).
this is the directive product-display
productDirectives.directive('productDisplayView',['$rootScope','$compile','$http','$templateCache' ,'$document',
function($rootScope,$compile, $http, $templateCache,$document){
return {
restrict: 'E',
link: function (scope, element, attrs) {
var templateUrl = 'users/catwizardAngularCore/app/partials/themes/' + scope.app.theme.themeName + '/partials/product-display.html';
$http.get(templateUrl, {cache: $templateCache})
.success(function (templateContent) {
element.replaceWith($compile(templateContent)(scope));
});
/* this doesn't work because the someElement doesn't exist*/
var newHash = 'anchor' + scope.anchorId;
var someElement = angular.element(document.getElementById(newHash));
angular.element(someElement).ready(function () {
$document.scrollToElement(someElement, 200, 2000);
});
}
}]);
There is a duplicate question with the correct answer, but it has not been accepted yet so I am copying the answer here.
The $anchorScroll has to occur after the page has been rendered,
otherwise the anchor doesn't exist. This can be achieved using
$timeout().
$timeout(function() {
$anchorScroll('myAnchor');
});
Credits to Tony
I have a list that looks like this:
Store 1
Section A
Section B
and so on...
Store 2
Section A
and so on...
So I open a modal window to create a new store. I return the store when I close the window, and so far that's working great!
<div ng-repeat="store in global.user.company2.store">
I need to push the callback store to $scope.global.user.company2.store[?]
modalInstance.result.then(function (newStore) {
// How do I get the IndexOf value of store?
// This is one of the stores in the ng-repeat
$scope.global.user.company2.store[???].section.push(newStore)
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
The way I'm sending a selected store into the modal is with resolve
$scope.createSection = function (size) {
var modalInstance = $modal.open({
templateUrl: 'createSection.html',
controller: 'SectionModal',
size: size,
resolve: {
items: function () {
// $scope.radio.model === store
// $scope.radio.model2 === section
return $scope.radio;
}
}
});
UPDATE: Here's a basic plunker http://plnkr.co/edit/UGN4niAO9nQETqhg8lxn
The radio model buttons aren't working. If you change resolve items to $scope.radio.model, the modal breaks. So I left it as is. I think maybe it has to do with the btn-radio being part of angular-ui-bootstrap?
When resolving your modal, box your returned object with the array index of the object.
For example:
$modalInstance.close({ radio: $scope.radio, index: $scope.items.indexOf($scope.radio) } );
Then, when resolving your modal's promise, simply unbox your object:
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem.radio;
$scope.selectedIndex = selectedItem.index;
}, function () {});
See the Angular-Bootstrap docs for more details.