Error when calling a directive in AngularJS - angularjs

I had the following directive:
app.directive('markdown', function () {
var converter = new Showdown.converter();
return {
restrict: 'E',
link: function (scope, element, attrs) {
var htmlText = converter.makeHtml(attrs.abc);
element.html(htmlText);
}
}
});
Which was not working correctly so the following was proposed.
app.directive('markdown', function () {
var converter = new Showdown.converter();
return {
restrict: 'E',
scope: {
input: '=input'
},
link: function (scope, element, attrs) {
scope.$watch(input,function(newvalue){
element.html(newvalue);
});
}
}
});
and I am calling it like this:
<markdown input="{{ q.qv.text }}"></markdown>
But it's giving me an error:
Error: [$parse:syntax] http://errors.angularjs.org/1.2.2/$parse/syntax?p0=q.qv.text&p1=is%20unexpe…ting%20%5B%3A%5D&p2=4&p3=%7B%7B%20q.qv.text%20%7D%7D&p4=q.qv.text%20%7D%7D
at Error (<anonymous>)
at http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:6:449
at Wa.throwError (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:152:467)
at Wa.consume (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:153:454)
at Wa.object (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:161:138)
at Wa.primary (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:152:102)
at Wa.unary (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:158:371)
at Wa.multiplicative (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:158:104)
at Wa.additive (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:157:466)
at Wa.relational (http://127.0.0.1:81/Scripts/angular-v1.2.2/angular.min.js:157:330)
Which when I click the link says:
Syntax Error: Token 'q.qv.text' is unexpected, expecting [:] at column 4 of the expression [{{ q.qv.text }}] starting at [q.qv.text }}].

IMHO, You should use.
<markdown input="q.qv.text"></markdown>
You don't need {{}}
Use, As per comment. This gives a new error "ReferenceError: input is not defined" pointing to the line "scope.$watch(input,function(newvalue){"
scope.$watch(function(){
return scope.input;
},function(newvalue){
element.html(newvalue);
});
EDIT
Complete Directive code
app.directive('markdown', function () {
return {
restrict: 'E',
scope: {
input: '=input'
},
link: function (scope, element, attrs) {
scope.$watch(function () {
return scope.input;
}, function (newvalue) {
element.html(+newvalue * 6);
});
}
}
});
Usage
<markdown input="myVar"></markdown>
Plunker DEMO

Related

How to adapt directive auto-focus to auto-focus="true"/"false"?

I'm not much in Angularjs and use the directive that put focus on particular element. It looks as following:
appModule.directive('autoFocus', function ($timeout) {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
$timeout(function () {
element[0].focus();
}, 0);
}
};
});
The usage looks as following:
<button auto-focus class="uui-button lime-green btn" ng-click="copyToClipboard()">
Copy
</button>
I'd like to rearrange directive above to have ability to write: auto-focus="true" or auto-focus="false".
UPDATE:
I've updated code as shown below, but it doesn't work that is the focus is always there regardless I write auto-focus="true" or auto-focus="false".
appModule.directive('autoFocus', function ($timeout) {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
var hasFocus = attrs.autoFocus;
if (hasFocus) {
$timeout(function () {
element[0].focus();
}, 0);
}
}
};
});
You can set the property to true or false and access the value via attrs.autoFocus inside directive's link function
Edit:
appModule.directive('autoFocus', function ($timeout) {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
var hasFocus = attrs.autoFocus;
if (hasFocus ==="true") {
$timeout(function () {
element[0].focus();
}, 0);
}
}
};
});

Dynamic controller

I have two nested directive and a few controllers and I want inject controller to second controller.
When I bind action to some button it work but list don't show up, some one know why?
Dynamic Controller directive
.directive("dynamicController", ["$compile", function($compile) {
return {
restrict: "A",
scope: {
dynamicController: "#"
},
compile: function(tElement, tAttrs) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
iElement.attr("ng-controller", scope.dynamicController);
iElement.removeAttr("dynamic-controller");
$compile(iElement)(scope);
}
}
}
}
}])
V1: http://codepen.io/anon/pen/LVeaWo
V2: http://codepen.io/anon/pen/EjoJVx
[ EDIT ]
I almost do it but it's one more problem.
I have two directive:
.directive("wrapDirective", function() {
return {
restrict: "A",
template: "<div dynamic-controller=\"Ctr1\">" +
"<button ng-click='action()'>Click</button>" +
"<ul>" +
"<li ng-repeat=\"item in list\">{{item}}</li>" +
"</ul>" +
"</div>",
scope: {
controller: "#wrapDirective"
}
}
})
and
.directive("dynamicController", function($compile) {
return {
restrict: "A",
scope: true,
controller: "#",
name: "dynamicController"
}
})
The problem is this line <div dynamic-controller=\"Ctr1\"> in warpDirective
I can't do something like this <div dynamic-controller=\"{{controller}}\">
CodePen with both cases: http://codepen.io/anon/pen/EjoJXV
You should use require and link to get the controllers of parent directives.
See Creating Directives that Communicate.
.directive('myDirective', function() {
return {
require: '^ngController', // <-- define parent directive
restrict: 'E',
scope: {
title: '#'
},
link: function(scope, element, attrs, ctrl) { // <-- get the controller via the link function
ctrl.doSomething();
}
};
The reason behind your code is not working is, {{}} interpolation value is not evaluated in you pre link function. So by compiling ng-controller with not value in it is throwing an error. You should use iAttrs.$observe as you are evaluating expression inside {{}}.
Code
var dynamicControllerObserver = iAttrs.$observe('dynamicController', function(newVal, oldVal) {
wrapElement.attr("ng-controller", scope.dynamicController);
wrapElement.append(iElement.html());
console.log(wrapElement)
iElement.html("");
console.log(iElement)
iElement.append(wrapElement);
$compile(wrapElement)(scope);
dynamicControllerObserver(); //destruct observe
})
Working Codepen
I did it, really helpful was this post: Dynamic NG-Controller Name
I modified it to my needs:
.directive('dynamicCtrl', ['$compile', '$parse', function($compile, $parse) {
return {
restrict: 'A',
terminal: true,
scope: {
dynamicCtrl: "#"
},
link: function(scope, elem, attr) {
var initContent = elem.html();
var varName = getName(elem.attr('dynamic-ctrl'));
update();
scope.$watch("dynamicCtrl", function() {
update();
})
function update() {
var wrapper = angular.element("<div></div>");
wrapper.append(initContent);
var name = $parse(varName)(scope.$parent);
wrapper.attr('ng-controller', name);
elem.empty();
elem.append(wrapper);
$compile(wrapper)(scope);
}
function getName(attr) {
var startIndex = attr.lastIndexOf("{") + 1,
endIndex = attr.indexOf("}");
return attr.substring(startIndex, endIndex);
}
}
};
}])
http://codepen.io/anon/pen/xGYyqr

Angular directive to add attributes to an element

I have the following HTML / Angular code on a form:
<span class="error" ng-if="model.errors['message.email']" ng-bind="model.errors['message.email'][0]"></span>
I would like to use less code so the following would render the same:
<span class="error" model-validator="message.email" validator-errors="model.errors"></span>
Note
When validator-errors is not present then the default would be "errors" so I would get:
<span class="error" ng-if="errors['message.email']" ng-bind="errors['message.email'][0]"></span>
UPTATE 1
I tried the following:
.directive('modelValidator', function () {
return {
restrict: 'A',
replace: false,
link: function (scope, element, attrs) {
var validator = element.attr('model-validator');
if (validator === "null")
return;
var errors = element.attr('validator-errors');
element.attr('data-ng-if', errors + "['" + validator + "']");
element.attr('data-ng-bind', errors + "['" + validator + "'][0]");
}
};
But this is not adding the attributes ...
UPDATE 2
The directive is working. I would like to just add a few things:
How to use an attribute to specify which variable contains the errors?
On the directive "scope.model.errors" would be "scope.allErrorsToDisplay".
Do I need to watch all scope? Can I only watch model.errors?
Or considering (1), watch the variable in "validator-errors"?
Here is my current code:
angular.module('Application')
.directive('validator', function () {
return {
restrict: 'A',
replace: false,
link: function (scope, element, attribute) {
scope.$watch(function () {
if (scope.model.errors) {
if (scope.model.errors[attribute.validator]) {
element.show();
element.text(scope.model.errors[attribute.validator][0]);
} else
element.hide();
} else
element.hide();
});
}
}
});
Update 3
This seems to do everything I need.
Does anyone has any suggestion to improve it?
angular.module('app')
.directive('validator', ['$parse', function ($parse) {
return {
restrict: 'A',
replace: false,
link: function (scope, element, attributes) {
scope.$watch(function () {
var errors = $parse('validatorErrors' in attributes ? attributes["validatorErrors"] : 'model.errors')(scope);
if (errors) {
if (errors[attributes.validator]) {
element.show();
element.text(errors[attributes.validator][0]);
} else
element.hide();
} else
element.hide();
});
}
}
}]);
I think your approach is too complicated. The power of directives is that you don't have to add other directives to accomplish what you want. If i'm understanding your question correctly, you want your element to display a message if the error exists. How about this?
<!-- html -->
<div ng-controller="mainController">
<div validate="email"></div>
<div validate="name"></div>
</div>
// controller
function mainController ($scope) {
$scope.model = {
errors: {
email: 'Your email is invalid!'
, name: undefined
}
}
}
// directive
function validate () {
return {
restrict: 'A'
, replace: false
, link: function (scope, elem, attr) {
if (scope.model.errors[attr.validate]) {
elem.text(scope.model.errors[attr.validate]);
}
}
}
}
codepen

Wrap Flexisel slider into Angular Directive

I try to use Flexisel with Angular but it fails to work somehow.
Here's plnkr link
var app = angular.module('angular.controls.flexSlider', [])
app.directive('flexCarousel', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
var options = scope.$eval($(element).attr('data-options'));
console.log(options);
$(element).flexisel(options);
}
};
});
I have forked your plunk, please check the fixes there. http://plnkr.co/edit/zH4u3MwkD6HX39I8PFEr?p=preview
You need a template for your directive in first case:
var app = angular.module('angular.controls.flexSlider', [])
app.directive('flexCarousel', function () {
return {
restrict: 'E',
transclude : true,
template : "<ng-transclude></ng-transclude>",
scope : {
options : "="
},
link: function (scope, element, attrs) {
$('#flexisel').flexisel(scope.options);
}
};
});

AngularJS Directive Value

I have an AngularJS directive. My directive is restricted to be used as an attribute. However, I want to get the value of the attribute. Currently, I have my attribute defined as:
angular.module('myDirectives.color', [])
.directive('setColor', function () {
return {
retrict: 'A',
link: {
pre: function () {
console.log('color is: ');
}
}
};
})
;
I use the attribute in the following manner:
<button type="button" set-color="blue">Blue</button>
<button type="button" set-color="yellow">Yellow</button>
I know that my directive is being used because I see 'color is: ' However, I can't figure out how to make it display 'blue' or 'yellow' at the end of that console statement. I want to get that value so I can do a conditional processing. How do I get the value of the attribute?
Thank you!
You can use the attributes argument of the link function:
angular.module('myDirectives.color', [])
.directive('setColor', function () {
return {
restrict: 'A',
link: {
pre: function (scope, element, attrs) {
console.log('color is: ' + attrs.setColor);
}
}
};
});
or you could create an isolate scope like this:
angular.module('myDirectives.color', [])
.directive('setColor', function () {
return {
restrict: 'A',
scope: {
setColor: '#'
},
link: {
pre: function (scope) {
console.log('color is: ' + scope.setColor);
}
}
};
});

Resources