Passing a $scope variable to a directive - angularjs

I am struggling to pass data from my model to a directive and have little to no idea how. I am an AngularJS newbie :).
My markup is as follows below. Currently witnessing two problems:
1) scope.$parent.companyName is always blank no matter what I type? I have declared an empty value because otherwise it's undefined and that seems like an anti-pattern.
2) Even if I get (1) working, it's relying on the layout of the model I give it because of $parent. How do I pass a string to the directive?
I have a view:
<ion-view>
<ion-header-bar class="bar-royal">
<h1 class="title">{{ registerTitle }}</h1>
</ion-header-bar>
<ion-content>
<div class="list list-inset">
<label>
{{ registerInfoLabel }}
</label>
<label class="item item-input">
<input type="text" placeholder="{{ companyNameLabel }}" ng-model="companyName">
</label>
<label>
<button class="button button-block button-royal" register-app>
{{ registerLabel }}
</button>
</label>
</div>
</ion-content>
</ion-view>
A controller:
angular.module('app')
.controller('RegisterController', ['$scope', '$appI18n', function ($scope, $appI18n) {
$scope.registerTitle = $appI18n.RegisterTitle;
$scope.registerLabel = $appI18n.RegisterLabel;
$scope.companyNameLabel = $appI18n.CompanyName;
$scope.registerInfoLabel = $appI18n.RegisterInfoLabel;
$scope.companyName = '';
}]);
And a directive:
angular.module('app')
.directive('registerApp', ['RegisterService', function (RegisterService) {
return {
restrict: 'AE',
link: function (scope, element, attrs) {
element.bind('click', function () {
alert(scope.$parent.companyName);
})
}
}
}]);

You can send a string in to the directive using an attribute. If you only have one parameter to send then you can use the directive itself like this:
<div register-app="companyName"></div>
And adding it to your directive scope:
scope: { registerApp : '=' },
Then it'll be available on your scope:
link: function (scope, element, attrs) {
console.log("cname ",scope.registerApp);
}
Here's an example of that working: http://jsfiddle.net/kgwkf02c/
Or you could send it in using it's own attribute (especially useful if you want to send in multiple values):
<div register-app cname="companyName"></div>
With the directive looking like:
scope: { cname : '=' },
link: function (scope, element, attrs) {
console.log("cname ",scope.cname);
}
Here's that version: http://jsfiddle.net/kgwkf02c/1/

Related

angular bind html tags from controller to html view

I need to render the $scope.htmlView tags in to html view.
I already tried using ng-bind-html. It renders the html tags but scope variable values will not appear.
How can I render both html tags and and scope variable values?
This is the controller:
$scope.newObj = {
billStatus : true;
eventTime : "2015-01-10"
};
$scope.htmlView = '<p>{{newObj.eventTime}}</p> <div style="margin-top: -15px;"><md-checkbox ng-checked="{{newObj.billStatus}}" style="margin-left: 0px;" aria-label="Bilable"><span style="margin-left:0px;">Bilable</span> </md-checkbox></div>'
Expected result is:
<p> 2015-01-10</p>
<div style="margin-top: -15px;">
<md-checkbox ng-checked="true" style="margin-left: 0px;" aria- label="Bilable">
<span style="margin-left:0px;">Bilable</span>
</md-checkbox>
</div>
I search over the internet over days and still could't find out a way to figure out this. please help me. thank you.
You have to do 2 things.
Use data-ng-bind-html=""
Use $sce.trustAsHtml(string)
UPDATED:
If you wont to use angular expressions, you have to compile them using
$compile.
You can read more via this $SCE
I will tell you a long way but it will help you.Make a custom directive like this.
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
Use as
<span dynamic="{{htmlView}}" >
Hi please check this fiddle
https://plnkr.co/edit/iqNltdDYv2n9Agke0C2C?p=preview
HTML
<div ng-controller="ExampleController">
<p >{{newObj.eventTime}}</p>
<p dynamic="htmlView"></p>
</div
and JS
(function(angular) {
'use strict';
angular.module('bindHtmlExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.newObj = {
billStatus : true,
eventTime : "2015-01-10"
}
$scope.htmlView = '<p> {{newObj.eventTime}}</p> <div style="margin-top: -15px;">Hello <md-checkbox ng-checked="{{newObj.billStatus}}" style="margin-left: 0px;" aria-label="Bilable"><span style="margin-left:0px;">Bilable</span> </md-checkbox></div>'
}])
.directive('dynamic', function($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, element, attrs) {
scope.$watch(attrs.dynamic, function(html) {
element[0].innerHTML = html;
$compile(element.contents())(scope);
});
}
};
});
})(window.angular);

AngularJS: Linking multiple scope variables inside external template

I am trying to build some custom directives for inputs with validations provided by ngMessages directive. Still, I can't link multiple variables from $scope to dynamically determine the form name and the input name. Here's my code so far:
The directive:
app.directive('textBox', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
label: "#",
fieldName: "#",
bindTo: "="
},
require: "^form",
templateUrl: '/WebClient/Directives/TextBox/textBoxTemplate.html',
link: function (scope, element, attrs, ctrl) {
$scope.formName = ctrl.$name;
}
};
}]);
The template:
<div>
<label>{{label}}</label>
<input type="text" name="{{fieldName}}" ng-model="{{field}}" required />
<div ng-messages="{{formName}}.{{fieldName}}.$error">
<div ng-message="required">You left the field blank...</div>
<div ng-message="minlength">Your field is too short</div>
<div ng-message="maxlength">Your field is too long</div>
<div ng-message="email">Your field has an invalid email address</div>
</div>
</div>
The usage:
<text-box bind-to="myField" field-name="myField"></text-box>
The issues I encounter are related to the ng-messages attribute value. Doesn't seem to work when I use curly braces and it renders the text "formName.fieldName.$error" if I don't. The other issue is related to the ng-model, the same scenario applies.
Thank you!
You can pass the formController, ctrl in your link method to directive scope like scope.form = ctrl;.
Then you can add <div ng-messages="form[fieldName].$error"> to access the $error property.
Curly braces are only required for the name of the input field. For ng-model you can directly add the model with-out curlies because ng-model requires two-way binding to work.
Please have a look at the demo below or this jsfiddle.
angular.module('demoApp', ['ngMessages'])
.controller('mainController', MainController)
.directive('textBox', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
label: "#",
fieldName: "#",
bindTo: "="
},
require: "^form",
templateUrl: '/WebClient/Directives/TextBox/textBoxTemplate.html',
link: function (scope, element, attrs, ctrl) {
//$scope.formName = ctrl.$name;
scope.form = ctrl;
}
};
}]);
function MainController($scope) {
$scope.myField = 'test';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.5/angular-messages.js"></script>
<div ng-app="demoApp" ng-controller="mainController">
<form name="testForm">
<text-box bind-to="model" field-name="myField"></text-box>
</form>
{{model}}
<script type="text/ng-template" id="/WebClient/Directives/TextBox/textBoxTemplate.html">
<div>
<label>{{label}}</label>
<input type="text" name="{{fieldName}}" ng-model="bindTo" required />
<div ng-messages="form[fieldName].$error">
<div ng-message="required">You left the field blank...</div>
<div ng-message="minlength">Your field is too short</div>
<div ng-message="maxlength">Your field is too long</div>
<div ng-message="email">Your field has an invalid email address</div>
</div>
</div>
</script>
</div>

Creating single custom directive for ng-click to perform multiple controller function

I have the following code:
<div>...
<div class="glyphicon glyphicon-filter ng-click="vm.add()" tabindex="1">
<a href='' tabindex="2"><img id="touch" ng-click="vm.multiply(xyz)"
src="/ui/assets/images/xxx.png"/></a>
<div class="glyphicon glyphicon-filter"ng-click="vm.showId()" tabindex="1" title="Filter">
</div>
..</div>
I want to create a custom single ng-click directive as its recommended for div (ng-click to be used for only buttons). I want to know if there is any way I can create a single directive for all 3 ng-click and call those 3 different functions in link at $apply?
Here you go: http://jsfiddle.net/psevypcs/2/
HTML
<div clicky="test()">test</div>
<div clicky="test2()">test2</div>
AngularJS-Controller
$scope.test = function(){
alert('hy');
};
$scope.test2 = function(){
alert('hy2');
};
AngularJS-Directive
angular.module('myApp')
.directive('clicky', Clicky);
function Clicky() {
return {
restrict: 'A',
scope: {
clicky: '&' // Take yourself as variable
},
link: function(scope, element, attrs){
$(element).on('click', function(e) {
scope.clicky();
});
}
};
}

How can i watch for change in a angular directive with $translate

Here's Fiddle Link
How can i watch for change in a directive? In this fiddle example using $translate to translate the content. Everything getting changed except the content in Directive.
HTML looks like this-
<div ng-app='demo'>
<div name="info" ng-controller="myctrl">
<label translate="TERMS_LABEL"></label>
<h4 translate="ZIPCODE_LABEL"></h4>
<p translate="LAST_NAME"></p>
<terms-conditions conditions="TERMS_CONDITIONS" checked="checked"></terms-conditions>
<button type="submit" ng-click="changeLanguage('de')" >Spanish</button>
<button type="submit" ng-click="changeLanguage('en')" >English</button>
</div>
directive looks like
demo.directive("termsConditions",['$translate',function($translate){
return {
restrict:"E",
scope:{
checked:'='
},
link: function(scope, element, attr) {
$translate(attr.conditions)
.then(function (translatedValue) {
scope.conditions = translatedValue;
});
},
template:
"<div class='terms row'><span class='col-md-12'>{{conditions}}</span></div><br><input
type='checkbox' ng-model='checked'><span>Yes, I agree to the terms and condtions</span>"
}
}]);
Is there a reason you can't translate in the template like so?
http://jsfiddle.net/UGLjh/75/
demo.directive("termsConditions",['$translate',function($translate){
return {
restrict:"E",
scope:{
checked:'='
},
link: function(scope, element, attr) {
attr.$observe('conditions', function (untranslatedValue) {
scope.conditions = untranslatedValue;
});
},
template:
"<div class='terms row'><span class='col-md-12'>{{conditions | translate}}</span></div><br><input type='checkbox' ng-model='checked'><span>Yes, I agree to the terms and condtions</span>"
}
}]);
If you know that your attribute won't be interpolated need not use $observe; just stick it on the scope like so:
link: function(scope, element, attr) {
scope.conditions = attr.conditions;
},

AngularJs: transclude through include

I try to make the directive with dynamic template
app.directive('boolInput', function () {
'use strict';
var
restrict = 'E',
replace = true,
template = '<ng-include src="template"></ng-include>',
scope = {
value: "=",
template: "#"
},
link = function (scope, element, attributes) {
// some stuff
};
return {
link: link,
restrict: restrict,
replace: replace,
template: template,
scope: scope,
transclude: true
};
});
So I use
template = '<ng-include src="template"></ng-include>'
and
scope = {
//..
template: "#"
}
to pass template url via attribute. All work great instead of one thing. There is how I use directive:
<bool-input data-value="item.value" data-ng-repeat="item in source" data- template="templates/boolInput.html">
{{item.Text}}
</bool-input>
{{item.Text}} - should be transcluded into template
That template:
<div class="checkbox">
<label class="checkbox-custom" ng-transclude>
<input type="checkbox">
<i class="icon-unchecked checked"></i>
</label>
</div>
but this does not happen, as a result I see:
<ng-include src="template" data-value="item.value" data-ng-repeat="item in data" data-template="templates/boolInput.html" class="ng-scope"><div class="checkbox ng-scope">
<label class="checkbox-custom" ng-transclude="">
<input type="checkbox">
<i class="icon-unchecked checked"></i>
<!-- There should be the text -->
</label>
</div></ng-include>
This was 2 years ago... For now we can pass a attribute to templateUrl function
templateUrl: function (elememt, attrs) {
return attrs.template || '<some default template path>';
}

Resources