Angular ng-init pass element to scope - angularjs

Is there a way to get the current element where my ng-init is currently binded on?
For example:
<div ng-init="doSomething($element)"></div>
I believe that there is a way for ng-click but I can't do this using ng-init like this:
<div ng-click="doSomething($event)"></div>
Controller:
$scope.doSomething = function(e){
var element = angular.element(e.srcElement);
}
How do I do this with ng-init?

Your HTML:
<div ng-app='app' ng-controller="Ctrl">
<div my-dir></div>
</div>
Your Javascript:
var app = angular.module('app', [], function () {});
app.controller('Ctrl', function ($scope) {
$scope.doSomething = function (e) {
alert(e);
};
});
app.directive('myDir', function () {
return function (scope, element, attrs) {
scope.doSomething(element);
};
});
From above, element will be your DOM object.

Don't do it.
As #CodeHater said, handling DOM manipulation in a directive is a better solution than engaging controller with the element.

I was also looking for similar thing but finally I created one more directive added to the child div element. In the directive code block I get the element object and placed all my event related function and other instructions over there. Also, I add the element to $scope object, this help me to use this object else where as well and no need to find it every time I need it.

Related

Angular JS: Directive content is not available in Java script function

I have a div which has ng-click. When I click on that div, it calls a function which gets script content from a Directive and I append that to another div and access the content of the script. But when I retrieve the content of the directive I am getting directive name not the content. I want to get the content.
The function I call:
$scope.someFunction = function(){
var appendHtml = $compile("<my-custom-directive></my-custom-directive>")($scope);
$("#someId").append(appendHtml)
//But when i append I am seeing as <my-custom-directive></my-custom-directive> in html not the actual content
$(""#someId"").find('script')
}
Directive:
app.directive('myCustomDirective', function ($compile) {
return {
restrict: 'E',
templateUrl: '/somecontent.html',
replace: true,
link: function ($scope, elem, attr, ctrl) {}
};
});
Somecontent.html
<script type="text/template">
<div class="arrow" style="left: 50%;"></div>
some elements here
</div>
</script>
The HTML where I call from:
<div ng-click="someFunction()">
<div id="someId">
<my-custom-directive></my-custom-directive>
//But Here I am seeing this, when calling
$(appendHtml).find('script') in my javascript function, after Javasciprt function call is done, It works fine. But i want to see actual content here when calling $(""#someId"").find('script')
<div>
</div>
it is not a good practice.
you can use ng-if and binding instead , like the follwing:
HTML
<div ng-click="someFunction()">
<div id="someId">
<div ng-if="$scope.isVisible">
<my-custom-directive></my-custom-directive>
</div>
//But Here I am seeing this, when calling
$(appendHtml).find('script') in my javascript function, after Javasciprt function call is done, It works fine. But i want to see actual content here when calling $(""#someId"").find('script')
<div>
</div>
controller:
$scope.isVisible = false;
$scope.someFunction = function(){
$scope.isVisible = true;
}
you can also pass isolate scope param to your directive and check the param in the directive template
It's possible that you're just not using jQuery or jqLite to select elements correctly.
Your someFunction might need to look more like this:
vm.someFunction = function () {
var appendHtml = $compile('<my-custom-directive></my-custom-directive')($scope);
angular.element(document).find('some-id-element').append(appendHtml);
};
I put together this plunk that I think might achieve what you're trying to do.
Does this approximate your goal?

Angular JS directives with isolate scopes and internal controllers

I haven't touched angular js in a while and back when I did write, we used a flavour with typescript which was pretty straightforward with me. Now I want to write vanilla angular js and I feel I am a bit confused.
Problem:
I have a directive with a few variables in its isolate scope and I basically want to bind to this directive that is spawned inside a for each <ul> to a click event. I tried with directly binding a function on ng-click and with link element e.t.c. bind on click, but it seems I am doing something wrong since with the first way nothing happens, with the second way the two-way bound variable is undefined.
Here it goes:
https://plnkr.co/edit/OOBMs8pYONLjUE9lQXla?p=preview
activity-header.html
<div>
<h4>
Activity Name: {{activity.activity_name}}
</h4>
<h6>
Activity Start Date: {{activity.activity_start_date}}
</h6>
<h6>
Activity End Date: {{activity.activity_end_date}}
</h6>
<h6>
Participants: {{activity.participants}}
</h6>
</div>
activity-header.js
var app = angular.module('mainApp');
/*
app.controller('activityHeaderCtrl', ['$scope', function($scope) {
$scope.activity='';
$scope.msg='';
$scope.check = function() {
alert($scope.msg);
};
}]);
*/
app.directive('activityHeader', function() {
return {
restrict: 'AE',
templateUrl: 'activity-header.html',
controller: ['$scope', Controller],
scope: {
activity:'=',
msg:'='
},
link: function($scope, $element, attrs) {
$element.bind('click', function($scope) {
alert($scope.msg);
})}
};
function Controller($scope) {
$scope.check = function() {
alert($scope.msg);
};
}
});
index.html
<html ng-app="mainApp">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="script-main.js"></script>
<script src="activity-header.js"></script>
<body>
<div ng-controller="ctrl">
<h1>
Major Bla bla System
</h1>
<ul>
<li ng-repeat="x in events">
<div activity-header activity="x" msg="greetingsfriend" ng-click="check()"></div>
</li>
</ul>
<h6>
Beta v.0.2
</h6>
</div>
</body>
</html>
script-main.js
var app = angular.module('mainApp', []);
app.controller('ctrl', function ($scope) {
//$scope.events = ["Elections", "Protest", "Martial Law", "X-mas Celebration"];
$scope.events = [
{"activity_name": "Elections", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1453"},
{"activity_name": "Martial Law", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1821"},
{"activity_name": "Protest", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1940"},
{"activity_name": "X-mas Celebration", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "2009"}
];
$scope.salute = function () {
alert('hello there');
};
});
(By the way, I'm using Mozilla Firefox, otherwise I'd have to host it e.g. on node.js for the same origin policy, don't know how to turn it off in chrome/ internet explorer).
depends on what you want to obtain.
For example, if you want to bind a function of your directive on click you don't need the link function. You can simply bind a click on your outer div with ng-click. See this example: http://jsbin.com/sanova/edit?html,js,output
But if you want to call a function on your parent controller you need to pass a reference to that function with a property on your directive. See this example: http://jsbin.com/peqasu/edit?html,js,output
As you can see i've put in both example a ng-click directive on the outer div in your directive template. On click the check function on the directive controller is invoked. In the first example simply alert the message, in the second one calls the greetFunction passed as a property of your directive.
Any idea on how to handle the click?
Your problem is that you are using $scope as the name for the first argument in the click handler function. That name is overriding the $scope argument from the linking function.
//BAD
link: function($scope, $element, attrs) {
$element.bind('click', function($scope) {
alert($scope.msg);
})}
Fix your code like this:
//GOOD
link: function(scope, element, attrs) {
element.on('click', function clickHandler(event) {
console.log(scope.msg);
});
}
AngularJS jqLite invokes the click handler with a JQuery Event Object as the first argument not $scope.
Is this the correct way to handle events on directives?
Why doesn't the ng-click event ever work to call the function I have in my directive's controller?
The ng-click directive binds to functions in the parent scope.
To bind click events to functions on the directive's scope, use element.on(). It's how ng-click gets the event from the browser. Look at the source code.
First of all you need to know the difference between smart and dumb components (directives).
Here you can read a very good article explain the difference from smart and dumb components written by Dan Abramov, the creator of Redux: https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
When you understand this difference you can try to write more dumb components and less smart one. This means that you need to keep all the logic on your parents components and pass it down to your dumb components.
In previous examples we do that only in the second one. In fact, in that example we keep the logic (our check function) in our parent component and only pass a reference to it. In this way the activity-header component have no idea of what to do when a click is done. It only know that it must call a function, what this function does is not its problem.
This is a good approach to have in a complex application, so you can reuse your components in different ways simply changing the reference function.

Bind and parse HTML content

I am using AngularJS v1.2.1.
The improved ng-bind-html directive allows me to trust unsafe Html into my view.
Example
HTML:
<div ng-repeat="example in examples" ng-bind-html="example.content()"></div>
JS:
function controller($scope, $sce)
{
function ex()
{
this.click = function ()
{
alert("clicked");
}
this.content() = function ()
{
//if
return $sce.trustAsHtml('<button ng-click="click()">some text</button>');
// no problem, but click is not called
//when
return $sce.parseAsHtml('<button ng-click="click()">some text</button>');
//throw an error
}
}
$scope.examples = [new ex(), new ex()];
}
My question is, how to bind HTML content that may contain Angular expressions or directives ??
If you need dynamic templates per element, as your question suggests, one solution would be to use $compile within a directive to parse the HTML within the context of the local scope. A simple version of this is shown in this Plunk.
An example directive:
app.directive('customContent', function($compile) {
return function(scope, el, attrs) {
el.replaceWith($compile(scope.example.content)(scope));
}
});
The corresponding HTML:
<div ng-repeat="example in examples">
<div custom-content></div>
</div>
Notice that, in the Plunk controller, I've pulled out the click function into the scope for simplicity, since in the template HTML you are calling click() in the context of the scope, not on the example object. There are a couple ways you could use a different click function for each example, if that's what you'd like to do. This egghead.io screencast has a good example of passing an expression into a directive explicitly; in your case, it could be a click function or the whole example object, depending on what you need.

Changing src of only hovered ng-include element, where value of src is a $scope variable

I have multiple ng-include elements that have src attribute set to $scope.template_url.
I want to change src of hovered element only to new template but changing it's value will change all of elements. How can i implement it?
Html code:
<section class="parent">
<div data-ng-include data-src="template_url"></div>
</section>
Javascript (in controller):
angular.element(document).on('mouseover', '.parent', function(){
$scope.$apply(function () {
$scope.template_url = "path/to/new/template.html";
});
});
Writing jQuery dom manipulation is dirty and also don't works:
$(this).attr('data-src', "path/to/new/template.html");
I'd suggest making this a directive. Directives have their own scope, so you can still do the "on hover use a different template" idea, but for each individual one that is hovered.
<div>
<div data-some-directive=""></div>
</div>
var myApp = angular.module('myApp',[]);
myApp.directive('someDirective', function() {
return {
controller: function ($scope) {
$scope.model = "Hello"
$scope.mouseover = function () {
$scope.model = "Hovered!";
};
},
scope:{},
restrict: 'AE',
replace: true,
template: '<div><input ng-mouseover="mouseover()" ng-model="model"></div>',
};
});
Heres a fiddle to see it in action.
Tweak the template variable in the directive to use a variable on your model for the include url.
By the way, angular already has a mouseover handler, so i've just linked that into the controller with ng-mouseover in the template.

Angular: How do you associate a controller and a DOM element explicitly

I have a DOM element that I want to associate with a controller, the usual way of course is using ng-controller. But in this case I cannot do this (for reasons that will take too long to explain).
Is there a way to do this association manually?
e.g.
<div id="foo">
...
</div>
angular
.module('APP', [])
.controller('FooCtrl', function ($scope) {
...
});
var $ele = $('#foo');
angular.bootstrap($ele, ['APP']);
// somehow associate #foo with FooCtrl without using ng-controller="FooCtrl"
Is this possible?
Thanks
You could try with a directive.
angular.module('APP').directive('fooCtrl', function () {
return {
controller: 'Foo'
};
});
then in your HTML
<div id="foo" foo-ctrl>

Resources