I am attempting to add a controller to a dynamically constructed div in angular. However, the controller doesn't seem to be loading and I cannot add corresponding events to the click function.
In the example below, I am constructing this div within a separate parent controller termed 'employeeTableCtrl'. Within the parent controller, when a user clicks the 'more info' button, the new divs are constructed. In the container of this child is where I am looking to attach a new controller.
$scope.moreInfo = function(employee) {
$("<div class='employeeWindow' ng-controller='employeeWindowCtrl'> " +
"<button class='closeButton' ng-click='close()'> x </button> </div>".appendTo("#employees");
}
And in the separate controller I have:
.controller('employeeWindowCtrl', [
'$scope', function ($scope) {
$scope.close = function() {
alert('clicked the x');
}
}
])
The divs are all being constructed correctly, but the the 'employeeWindowCtrl' is not being attached such that my 'click()' function is not being executed.
Does anyone have any tips? Maybe I am approaching this all wrong?
Thanks
What you're looking for is a directive - a chunk of html that has a sort of private controller via the link function. Create the directive in a separate template, place your controller functionality (if it indeed is appropriate for a controller) in the directive's link function and use ng-show to reveal on click. If we had more code to play with I could give a better example of all of this.
https://docs.angularjs.org/guide/directive
Related
I'm trying to use a Chrome Extension as a complimentary tool for the web app I'm developing.
I used chrome.tab.executeScript to manipulate the DOM of the web app and append a button inside a DIV.
chrome.tabs.executeScript({
code: 'var e = document.createElement("div");' +
'e.innerHTML = "' +
'<button ng-click="myfnc()"></button>' +
'";' +
'document.getElementsByTagName("body").appendChild(e);'
});
The button is added/appended as expected.
<body>
<div>
<button ng-click="myfnc()"></button>
</div>
</body>
The button has ng-click attribute that points to function on the web app. The function is just a simple alert call.
myfnc():
alert('Hello!');
However, when I click on the button nothing happens. Do you have any idea why? Can injected html coming from Google Chrome Extension interact directly with the web page's code?
Creating an element with the attribute ng-click does not inform Angular that the element exists within the page, as parsing of the document occurs once during bootstrap. You therefore have an element which exists 'outside' of any Angular scope, meaning the attribute ng-click just exists and has not caused the corresponding directive (ngClick) to be invoked.
Providing of course that the page has Angular, you will want to use the $compile service along with the desired $scope to compile the element after it has been inserted into the page.
A comprehensive solution is outside of the scope of your question. (Why does nothing happen when the button is clicked?) If you want to read more about using injected code with Angular, read up on:
the angular.element#scope() method, which lets you pick up the $scope object of an element,
appending an angular.element using the append() method available on angular elements
using the derived $scope object in compiling elements such that Angular is aware of it
The steps you want to take are something like...
Get the $scope you want to insert the element within:
var angular = document.querySelector('body');
var scope = angular.element(angular).scope();
Insert the new element into the page:
var newElem = angular.element('div');
angular.append(newElem);
$compile the element with this $scope:
$compile(newElem)(scope);
More information on dynamically creating Angular elements can be found in the answer to this question.
For a while now, I've been following an Angular directive TypeScript pattern that I really like. I give the directive its own isolated scope by creating a new controller.
I've run into a situation where I need to call a function within my Angular directive from outside of the directive.
For example, I have a really simple function that opens a popup within my directive. The directive's controller has something like:
public openPopup() {
this.uiClasses.popup = "open";
}
The corresponding view has a few notable elements like:
<div ng-click="vm.openPopup()">Open the pop up</div>
<div ng-class="vm.uiClasses.popup">the actual popup</div>
With some really basic CSS, this works like a charm. But, what if I have a controller that creates this directive, and wants to trigger the directive's openPopup function. I want to do something like this:
class PageController {
private scope: any = null;
static $inject = ["$scope"];
constructor($scope: any) {
$scope.vm = this;
}
public openTheDirectivePopup() {
// from here, how can I call the openPopup on a specific directive?
}
}
The corresponding view:
<div ng-click="vm.openTheDirectivePopup()">I can open the popup inside the custom directive</div>
<my-custom-directive></my-custom-directive>
I also want to be able to have multiple instances of these directives on the same page without conflict.
It seems like this should be do-able, but I can't quite wrap my head around it. Any suggestions?
What I would do in that case is add a "isOpen" attribute to your directive, and toggle that value true / false from your ng-click call.
It would look like this in your HTML:
<div ng-click="vm.isOpen = true">I can open the popup inside the custom directive</div>
<my-custom-directive isOpen="vm.isOpen"></my-custom-directive>
I have an Angular custom directive which uses a very simple carousel template which only has 2 slides loaded and bound because I expect to repeat lots of them on a page. When the user interacts with the directive I want to load an additional template containing the rest of the slides and compile it under the same scope as everything else in the directive.
This is how I am doing it so far. This function is inside my directive and is called when the user clicks the "next" button.
function loadExtraSlides(){
$templateRequest('/templates/propertyCardExtraSlides.tpl.html').then(function(template) {
$compile($(carouselEl).append(template).contents())($scope);
// Template is loaded
}, function() {
$log.error('Error loading card slides template');
});
}
}
}
This seemed to work at first because the template is loaded and inserted inside the carousel, but unfortunately the new template isn't bound to the scope correctly. If I put {{images}} into the main template is outputs an array of image URLs from my directive's scope. If I put the same thing in my template which is being imported and compiled it just outputs "{{images}}" to the DOM.
Hopefully I'm doing something simple wrong. Any help would be really appreciated.
I have defined a directive in angular.js. That directive has a link function and a controller function, and no template, so all the view is generated in the link function. In the link function I am doing the following:
var button=angular.element("<a>");
button.addClass("ng-click: previousLink();");
//previousLink() is a function defined in the scope.
//I am doing it like that, because before that one I attempted to do:
//button.prop("ng-click", "previousLink()");
//button.text("Previous");
//but for some reason it was showing on html as <a>Next</a>, without adding the property.
It does not work. If I click the button it does nothing. If, instead of doing this in the link function in code I were doing it using a template, it would work. For some reason I need to make some manipulations using jquery in the link function. What should I do? Is there anyway to make this work, or would I have to use both template and link function and combine things there?
To use $compile you need to follow your existing code with something like:
$compile(button.contents())(scope);
If you want it to be dynamic, you can put this inside a $watch like so:
link: function (scope, ele, attrs) {
scope.$watch(attrs.yourval, function(html) {
var button=angular.element("<a>");
button.addClass("ng-click: previousLink();");
$compile(button.contents())(scope);
});
}
$compile attaches the scope (supplied as a parameter) to the html you have defined. This will make your button clicks work properly.
I am trying to add an angular JS module inside an already existing code. I'm actually trying to add a new piece of code inside it. The workflow goes like this. When a button is clicked, the JS takes a template and adds it to the dom. In this added template, i would like to insert the new angular JS module. I am trying to atleast show hello world inside the module but haven't been successful.
Let's say when a button is clicked, i'm adding the below tag to the dom
<div patient-details ng-controller='patientDetailsCtrl' id='patientDetails'></div>
This is added through jquery or javascript. How do i make it work with the below directive
angular.module('patientDetailsModule',[])
.directive('patientDetails',function($compile){
return{
//restrict: 'E',
template: "<div>Hello World!!!{{name}}</div>"
};
});
You need to use $compile. $compile() will make sure all the Angular code in your html snippet will be compiled!
Here is an example.
http://plnkr.co/edit/7Wr3oAtvZ8cn31uFFEOs?p=preview
Send Message from nc-click to directive
Directive receives message, compiles html and appends new element
var template = "<div patient-details ng-controller='patientDetailsCtrl' id='patientDetails'>Element added</div>";
var newElement = angular.element(template);
$compile(newElement)(scope);
element.append(newElement);
// can also use element.replaceWith(newElement);