I want to create a really simple confirmation box using UI-modal, which I have successfully used to make complicated modals that load their template and controller from external files in the past.
It's so simple though that I don't want to rely on external template and controller files, just a simple box with a close button which is somehow wired up to a controller declared directly on the modal instance.
Here is what I have tried unsuccessfully...
var modalInstance = $modal.open({
template: "<div>Message goes here...<button ng-click='cancel()'>Continue</button></div>",
controller: function(){
$scope.cancel = function(){
alert("Cancelled");
};
}
});
Looks like you need to inject $scope into your controller function
controller: function($scope){
The scope of the modal template is not the same as the scope in the controller that you've defined the modal instance in.
The reason you're not getting undefined errors is $scope is a closure variable so adding .cancel() to it works just fine. But, since it isn't the same scope of the modal, so the ng-click doesn't see a .cancel() on its scope.
I replicated in this jsbin: http://jsbin.com/gejuxije/1/edit
Edit:
Since you mentioned you didn't want external files for a template, here's a demo of how to define the template for the modal inside the template of the view it is used on.
http://jsbin.com/gejuxije/2/edit
You can put html inside of an inline script...
<script type="text/ng-template" id="myModalTemplateName.html"></script>
The value you pass to 'template' needs to be valid HTML, and ideally should contain the appropriate modal CSS classes.
You may also need to pass in the scope for the controller.
var modalInstance = $modal.open({
scope:$scope,
template: "<div>Message goes here...<button ng-click='cancel()'>Continue</button></div>",
controller: function(){
$scope.cancel = function(){
alert("Cancelled");
};
}
});
In general I have not had to do this, but since you are defining the controller in the open method it may be necessary. According to the docs it should create a new scope as a child of rootScope, but I suspect your mileage is varying. I wish the instructions on the website were a little more informative on this topic.
You may also want to try $close and $dismiss. I've never tried them, but since you are not having luck with the scope variable these might be what you need.
I am just trying to do something similar and stumbled across this. I know it's old but it might help someone.
Simply put
modalInstance.close();
in the cancel function
Related
I have a simple modal that appears when the user enters a page, but it is creating two of them. I have looked through the app and there are not two calls to the modal.
Here is the controller for it:
angular.module('rokoApp')
.controller('FinanceCtrl', function($scope, $modal) {
$modal.open({
templateUrl: 'includes/modal.html',
controller: function ModalInstanceCtrl($scope, $modal,$modalInstance){
console.log('opened')
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
});
will be much better if you give us an example of functional code in plunker or jsfiddle, because the problem could be in another place.
For example:
When we started creating an app with AngularJS usually we put ng-controller in a upper tag and write the first lines of our app. The problem is that some times when we added routing we forget remove the ng-controller and then the controller is executing twice. The first time with the configuration of the module and again with the processing of the html.
So the solution here is to remove the tag in the html if we use routing or delete the controller property of routing and keep the ng-controller in the html.
I will let you the two codes:
With the error: http://plnkr.co/edit/TmQ5QhjD55WTurQNaEIv
Without the error: http://plnkr.co/edit/1xGUGEvAZ6jUBs8CbhTT
I'm looking to have a function run every time an angular directive updates. In my case, I have an array of modal configurations that get used on a modal markup template.
Every time the template is used to generate a modal due to a change in the model, I want to run a positionModal() method.
scope.$watch in the link function doesn't seem to notice when I change the model, and I cant think of any other way of doing this. I tried a post-link function thinking that the compile function would get called when the directive was applied, but that doesn't seem to work either. Here is my example controller:
MyApp.controller("ModalController", function () {
//Define scope vars
$scope.modals = [];
$scope.$on("modalTrigger", function (event, settings) {
$scope.modals.push(settings);
});
});
Note: I've simplified the controller here- know that it DOES work.
Here is the template code:
<div class="modalParent" ng-controller="ModalController">
<div id="{{modal.id}}" class="modal" ng-class="modal.type" ng-repeat="modal in modals">
<div class="content">
<h2 ng-show="modal.title">{{modal.title}}</h2>
<p>{{modal.message}}</p>
<button>{{modal.button}}</button>
</div>
</div>
</div>
The directive is currently like this:
MyApp.directive("modalParent", function () {
var positionModals = function (element) {
element.find(".modal .content").each(function () {
//position logic here
});
};
return {
restrict: "C",
compile: function (tElement) {
positionModals(tElement);
}
};
});
Note: Also simplified for the purposes here.
The positionModals() call works when the first modal gets pushed to the array. After that, it stops working.
I've tried using the linking function as well, same result. scope.$watch(modals, function(){...}) does not work.
Can somebody help me figure out what I'm doing wrong?
Figured it out!
I was applying the directive to the parent, ".modalParent".
The ng-repeated element in this case is the modal itself ".modal".
You would want the directive to run on elements that get updates as the model changes, because then the linking function will get called each time the element is instantiated, rather than sitting and watching the parent and trying to update from there.
Hope this helps somebody.
Instead of calling like this, my approach is to write this in the services and inject that services in the controller wherever you want to get that function or the data to be notified as,
Services.js
as.service("xyzservice",function(factoryname){
//here the code goes...
})
Now inject in Controller,
ac.controller("controllername",function(xyzservice){
})
ac.controller("controllername",function(servicename){
})
ac.controller("controllername",function(xyzservice){
})
Here we have injected it in the two controller, we can get it.
So I have a clearNotification function I want to trigger when I click the '#upload' button. I set an ng-click on that button to trigger notify().
What I'm wondering is if it's a violation of separation of concerns to put that clearNotification function within notify(). Is it better to add that as another ng-click on '#upload'? Or is this where directives come in?
Would love any input on this.
So far, this is what my code looks like:
HTML:
<button id="upload" ng-click="notify()">Upload</button>
Controller:
$scope.clearNotification = function() {
$scope.notification = '';
};
$scope.notify = function() {
$scope.clearNotification();
...
};
There's nothing wrong with calling controller functions from other controller functions.
If the clearNotification function has some business logic, then add it to a service(and inject that service into your controller). Thats the correct way to seperate components.
Should this be a directive? Only if this is a re-usable component that can live alone.
Im new at AngularJS, and i have this problem;
I fill part of my view with html from a variable in my controller:
<div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div>
Everything goes fine until i decide to run a script. The script is shown, but it doesn't run. I think the problem is the view is filled with my variable controllers after loading the page, so the script doesn't run.
The reason that i am using a variable in my controller to storage the script is because i will have to get the script from somewhere else, and its frequently changed.
Is this a viable way to run my script?.
Here is an example of my code:
View:
<div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div>
Controller:
.controller('browseCtrl', function($scope,$sce) {
$scope.video = '<div id="idxx1" style="width: 460px; height: 290px;" itemprop="video" itemscope itemtype="http://schema.org/VideoObject"></div><script>addeere3ejs("idxx1", "172653", "24431581", "1_fq2w6oc2");</script>';
$scope.deliberatelyTrustDangerousSnippet = function() {
return $sce.trustAsHtml($scope.video);
};
})
If my question it is unclear i would try to explain it better.
You can use the viewContentLoaded event in your controller.
$scope.$on('$viewContentLoaded', function(){
// Run after view loaded.
});
Not exactly sure if ng-bind-html will allow a script to be ran like that. You may need to wrap it in angulars brackets to auto-run on load.
<div ng-bind-html="{{deliberatelyTrustDangerousSnippet()}}"></div>
My work around was to run a $scope function like this with a known variable(s) that will change:
{{postBind(results)}}
Then have a method in your controller to do this
$scope.postBind = function (obj) {
running_my_extenal_methods();
}
http://plnkr.co/edit/GRVZl35D1cuWz1kzXZfF?p=preview
In the custom fancybox (aka lightbox, a dialog) I show contents with interpolated values.
in the service, in the "open" fancybox method, i do
open: function(html, $scope) {
var el = angular.element(html);
$compile(el)($scope); // how to know when the $compile is over?
$.fancybox.open(el); // the uncompiled is shown before the compiled
}
The problem is that the content in the dialog is loaded before the end of the $compile, so after less than a second i got a refresh of the dialog content with the values.
The plunkr works, but i want to avoid that the "el" is shown before it gets totally compiled: i want to show it only after the $compile has finished his job
Is there a way to know when the $compile it's over so i'll show the content on fancybox only after that?
You can't inject $scope into services, there is nothing like a singleton $scope.
So instead of $compile(el)($scope); try:
var compiledEl = $compile(el);
....
The $compile returns compiled data.
as a side note
I would provide service to directive and compile it into directive instead. I think it's the right way.
I've had the same problem with the ngDialog modals and popup provider. I needed to position the dialog based on its height. But the height depended on the compiled DOM.
I eventually found a solution using $timeout, like described in that post: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering/
For your code, it would give something like that:
open: function(html, $scope) {
var el = angular.element(html);
$compile(el)($scope);
$timeout(function() {
$.fancybox.open(el);
}, 0);
}