Unable to retrieve value from parent scope - javascript

I am still learning AngularJS and I'm having some issues with scopes in my implementation.
The following is my controller and directive definition:
angular.module('myModule', [])
.controller('myController', ['$scope', function($scope) {
$scope.parentVariable = "Test";
}]);
.directive('myDirective', [function(){
return {
restrict:'AEC',
link: function(scope, element, attrs) {
var child = scope.$eval(attrs.myDirective);
}
}
}]);
The following is my HTML:
<div ng-controller="myController"
<div my-directive="parentVariable"></div>
</div>
I am trying to retrieve the value of parentValue, however when I run the code child is undefined.

You had a few typos, once you clean them, it all works. Also, if you want to use a variable in the DOM, you need to make it a scope property. See below:
angular.module('myModule', [])
.controller('myController', ['$scope', function($scope) {
$scope.parentVariable = "Test";
}])
.directive('myDirective', [function(){
return {
restrict:'AEC',
template: '<p>{{child}}</p>',
link: function(scope, element, attrs) {
scope.child = scope.$eval(attrs.myDirective);
}
}
}])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myModule" ng-controller="myController">
<div my-directive="parentVariable"></div>
</div>

Related

Why won't $compile work with service using a directive?

Please have a look at this example, since it is the best way to explain the problem.
In this example if you click the directive link, it does not compile the template, but instead displays it as "{{1+1}}".
On the other hand if you click the "Simple link" it compiles the template and displays "2" instead.
angular.module('myApp', [])
.provider('$popup', function() {
var service = {};
this.$get = ['$compile', '$rootScope', function($compile, $rootScope) {
var template = $('<div>{{1+1}}</div>');
service.go = function() {
$(document.body).append(template);
$compile(template)($rootScope);
}
return service;
}];
})
.directive('popupLink', ['$popup', function($popup) {
return {
restrict: 'A',
scope: {},
link: function link(scope, element, attrs) {
element.click(function() {
$popup.go();
return false;
});
}
};
}])
.controller('mainCtrl', ['$scope', '$popup', function($scope, $popup) {
$scope.go = function() {
$popup.go();
};
}])
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="myApp" ng-controller="mainCtrl">
<a ng-href="/test" popup-link>Directive link</a>
Simple link
</div>
My question is why isn't the template compiling with the directive? (but it does in the controller)
And how do I fix it so that it compiles in the directive also?
P.S. Here is the jsbin link in case you want to play around with the code:
http://jsbin.com/vuzutipedu/edit?html,js,output
The directive needs to do scope.$apply():
link: function link(scope, element, attrs) {
element.click(function() {
$popup.go();
//ADD apply
scope.$apply();
return false;
});
The click event handler executes outside the AngularJS framework. A framework digest cycle needs to be performed to execute the watcher for the {{1+1}} interpolation.
It works with the ng-click directive because that directive includes scope.$apply.
For more information, see
AngularJS Developer Guide - Integration with the browser event loop
DEMO
angular.module('myApp', [])
.provider('$popup', function() {
var service = {};
this.$get = ['$compile', '$rootScope', function($compile, $rootScope) {
var template = $('<div>{{1+1}}</div>');
service.go = function() {
$(document.body).append(template);
$compile(template)($rootScope);
}
return service;
}];
})
.directive('popupLink', ['$popup', function($popup) {
return {
restrict: 'A',
scope: {},
link: function link(scope, element, attrs) {
element.click(function() {
$popup.go();
//ADD apply
scope.$apply();
return false;
});
}
};
}])
.controller('mainCtrl', ['$scope', '$popup', function($scope, $popup) {
$scope.go = function() {
$popup.go();
};
}])
<script src="//unpkg.com/jquery"></script>
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app="myApp" ng-controller="mainCtrl">
<a ng-href="/test" popup-link>Directive link</a>
Simple link
</div>
Try this in $get, instead of $compile(template)($rootScope)
$compile(angular.element(template))(angular.element(template).scope());
Let me know if it works

Update scope from a directive on mousedown Angularjs

I am having an issue updating the scope in a controller from a directive. Below are the basics of what is going on.
myApp.directive('myDirective', ['$document', function($document) {
return {
link: function(scope, element, attr, controller) {
angular.element(element).bind('mousedown', function(event){
scope.name = 'test';
});
}
}
}
myApp.controller('myController', ['$scope', function($scope){
$scope.name = 'something';
}]);
The html:
<p>{{name}}</p>
<p my-directive>Click me</p>
The result above is always something that was set in my controller, and is never updated to test.
I have tried a $watch in my controller but it never updates, so i have to be just missing something...
Since you are using jQuery .bind functionality you have to use scope.$apply to notify Angular that you have updated a scope property.
angular.module('app', [])
.directive('myDirective', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
angular.element(element).bind('mousedown', function(event) {
scope.$apply(function() {
scope.name = 'test';
});
});
}
}
})
.controller('ctrl', function($scope) {
$scope.name = 'something';
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<p>{{name}}</p>
<p my-directive>Click Me</p>
</div>
Directives have their own isolated scope. If you want to share something between a directive's scope and a controller's scope, you need to include it in the directive definition like this:
return {
scope: {
name: '='
},
link: function(scope, element, attr, controller) {
angular.element(element).bind('mousedown', function(event){
scope.name = 'test';
});
}
}
This tells Angular that you want to share the scope variable name between the directive and whatever scope calls that directive. Using the equal sign (=) defines it as two-way data binding.

How to make an angular directive to work only in one controller

i have many controllers and i have a directive. and now i want this directive to work in only one particular controller.
Plunker Link: http://plnkr.co/edit/onDmKl?p=preview
JS:
var app = angular.module('plunker', []);
app.controller('MainCtrlA', function($scope) {
});
app.controller('MainCtrlB', function($scope) {
});
app.directive('ngElevateZoom', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.attr('data-zoom-image', attrs.zoomImage);
$(element).elevateZoom();
}
};
});
$(document).ready(function() {
$('#native').elevateZoom();
});
HTML:
<div ng-controller="MainCtrlA">
<img ng-elevate-zoom ng-src="http://s27.postimg.org/xyoknslhf/blue_bird_wallpaper_small.jpg" zoom-image="http://s27.postimg.org/v5h4f601v/blue_bird_wallpaper.jpg" />
</div>
<div ng-controller="MainCtrlB">
<img ng-elevate-zoom ng-src="http://s27.postimg.org/xyoknslhf/blue_bird_wallpaper_small.jpg" zoom-image="http://s27.postimg.org/v5h4f601v/blue_bird_wallpaper.jpg" />
</div>
now i want that ngElevateZoom directive to work only in MainCtrlA.
im no expert in angular, so go easy on me ;)
A nice way to structure your AngularJS application is to modularize every component, that means you create your controllers, directives, filters, etc. and wrap them into a module:
var myApp = angular.module('myApp', ['moduleA', 'moduleB']);
angular.module('moduleA', [])
.directive('myDirectiveA', function() {})
.controller('MyCtrlA', function($scope) {});
angular.module('moduleB', [])
.directive('myDirectiveB', function() {})
.controller('MyCtrlB', function($scope) {});

Why this code does not works in AngularJS 1.2?

I have this code, written with Angular 1.2: http://jsfiddle.net/VmkQy/1/
<div ng-app="app">
Title is: <span my-directive data-title="Test title">{{ title }}</span>
</div>
angular.module('app', [])
.directive('myDirective', [function() {
return {
restrict: 'A',
scope: {title:'#'},
link: function($scope) {
alert($scope.title);
}
}
}])
;
Scope has a title property, but it does not rendered. Why?
If I change directive config to scope:true, it will works fine: http://jsfiddle.net/VmkQy/2/
angular.module('app', [])
.directive('myDirective', [function() {
return {
restrict: 'A',
scope: true,
link: function($scope, $element, attrs) {
$scope.title = attrs.title;
alert($scope.title);
}
}
}])
;
This is a bug or feature in Angular 1.2? Older version works fine in all this cases: http://jsfiddle.net/VmkQy/3/
The {{title}} inside of your <span /> gets replaced. Add template: "{{title}}" to your directive and it works:
http://jsfiddle.net/VmkQy/5/

Angular js access associated controller from within directive

With HTML like this...
<div ng-app="myApp">
<div ng-controller="inControl">
I like to drink {{drink}}<br>
<input my-dir ng-model="drink"></input>
</div>
</div>
and javascript like this...
var app = angular.module('myApp', []);
app.controller('inControl', function($scope) {
$scope.drink = 'water';
});
app.directive('myDir', function(){
return {
restrict: 'A',
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});
Why can I not access the controller from within my directive? Why is my call to ctrl giving me undefined?
EDIT: add demo...
Fiddle available here: http://jsfiddle.net/billymoon/VE9dX/
see multiple controller can be attached with one app and simillarly multiple directive can be attached with one app, so if you wants to use one controller in one directive than you can set the controller property of directive to the name of the controller you wants yo attach with like in your case
app.directive('myDir', function(){
return {
restrict: 'A',
controller: 'inControl'
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});
Despite this working with require:ngModel, this still isn't the best approach as it ties the directive directly to the controller. If you want your directive to communicate with your controller, you could be setting and reading off the scope.
HTML:
<div ng-app="myApp">
<div ng-controller="inControl">
I like to drink {{drink}}<br />
<input my-dir="drink"></input>
</div>
</div>
JS:
var app = angular.module('myApp', []);
app.controller('inControl', function($scope) {
$scope.drink = 'asdfasdf';
});
app.directive('myDir', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
console.log(scope[attrs.myDir]);
}
};
});
Alternatively you can use my-dir="{{drink}}" and read it as attrs.myDir.
http://jsfiddle.net/8UL6N/1/
Adding require: 'ngModel', fixed it for me - not sure if there is another way to specify it...
app.directive('myDir', function(){
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, element, attrs, ctrl) {
// why is this logging undefined?
console.log(ctrl);
}
};
});

Categories

Resources