I have list of Object of person type in my controller when I loop through them it works fine and display name of all person from list.
I have define a controller to display data in structured why but its not allowing to bind scope of custom directive to value of person name
this piece of works fine
<div ng-app="myapp">
<div ng-controller="MyController">
<div ng-repeat="per in person">
<!-- <test user=" -->
{{per.firstName}}
<!-- "></test> -->
</div>
But When I try to bind scope of custom directive to object first name ,AngularJS throw error
Error: [$parse:syntax] Syntax Error: Token '{' invalid key at column 2 of the expression [{{per.firstName}}] starting at [{per.firstName}}].
<div ng-repeat="per in person">
<test user=" {{per.firstName}}"></test>
</div>
</div>
</div>
AngularJs cond:
var myapp=angular.module('myapp',[]);
myapp.controller('MyController',function($scope){
$scope.person=[
{firstName:"ali1",
lastName:"ahmad"
},
{firstName:"ali2",
lastName:"ahmad3"
},
{firstName:"ali4",
lastName:"ahmad"
},
{firstName:"ali5",
lastName:"ahmad"
},
];
});
myapp.directive('test',function(){
var directive={}
directive.restrict="E";
directive.template="Name : {{user.firstName}}";
directive.scope={
user:"=user"
}
return directive;
});
How to bind custom directive with value of object directive.?
Try this:
<test user="per"></test>
html:
myapp.directive('test', function () {
return {
restrict: 'E',
scope: {
user: '='
},
template: 'Name : {{user.firstName}}'
};
});
when you bind to a scope you just pass the object, no need for {{}}, so
user="per.firstName"
Change this line
<test user=" {{per.firstName}}"></test>
To
<test user="person"></test>
And use ng-repeat inside the directive.
First send the data from your controller to your directive like this
<test user="person"></test>// Here you are sending whole array
Then receive your user which is containing refrence of person
Then inside your directive receive user in some variable as you have done this inside scope of directive user: "=user"
Related
I'm trying to pass in some attributes to my <custom-input> directive. Like so...
<custom-input type="text" name="first_name" title="First Name"></custom-input>
However, I'm getting a syntax error for the line where I pass the attribute to ng-model in the template.
I'm not sure what I'm doing wrong? Everything was working before I tried to move into a custom directive.
Directive
.directive('customInput', function() {
return {
restrict: 'E',
scope: {
type: '#type',
name: '#name',
title: '#title'
},
templateUrl: './assets/templates/custom-input.html',
controller: function() {
this.data = {}
this.focus = null;
},
controllerAs: 'input'
};
})
Template
<div class="Form__field">
<input
ng-model="input.data.{{name}}"
ng-class="{'Form__input--is-filled': input.data.{{name}}.length > 0}"
ng-focus="input.focus='{{name}}'"
ng-blur="input.focus=null"
class="Form__input"
type="{{type}}"
name="{{name}}"
placeholder="{{title}}"
/>
<label
ng-show="input.data.{{name}}.length > 0"
ng-class="{'Form__label--is-active': input.focus === '{{name}}'}"
class="Form__label"
for="{{name}}"
>{{title}}</label>
<div
class="Info Info--default"
ng-show="input.focus === '{{name}}'">
</div>
</div>
Error
Error: [$parse:syntax] Syntax Error: Token '{' is not a valid
identifier at column 12 of the expression [input.data.{{name}}]
starting at [{{name}}].
Before:
input.data.{{name}}
After:
input.data[name]
Your inner scope is getting type, name, and title attached directly to it. By defining the scope in the directive definition, you are declaring an isolate scope--one that no longer has access to the outer scope. You're also not passing in your input object.
What you have is the same as doing this inside the controller:
scope.name = 'first_name';
scope.title = 'First Name';
scope.type = 'text';
If you follow #bchemy's suggestion, you'll get a new property on your empty input.data object called first_name. And then the contents of the input would go into that. But there's no reason to expect that anything will come into it, because you didn't pass anything in that you're putting into that variable.
Here i want to update controller scope value as per change in directive scope but its only working outside the ng-repeat and its not working inside ng-repeat..
HTML
<div ng-app="app">
<div ng-controller="MainCtrl">
<div>
<h3>
outside repeat
</h3>
<br> Name <strong>{{name}}</strong>
<div class="directive" my-directive name="name"></div>
<button ng-click="run()">See changes</button>
<br>
<br>
<h3>
Inside repeat
</h3>
<br>
<div ng-repeat="(k,v) in rawdata">
{{k}} {{v.key}} Name <strong>{{name}}</strong>
<div class="directive" my-directive name="name"></div>
<button ng-click="run()">See changes</button>
<br>
</div>
</div>
</div>
JS
var app = angular.module("app", []);
app.controller("MainCtrl", function($scope) {
$scope.name = "HappyNewYear2016";
$scope.run = function() {
alert($scope.name);
}
$scope.rawdata = [{
key: "event1",
}, {
key: "event2",
}];
});
app.directive("myDirective", function() {
return {
restrict: "EA",
scope: {
name: "="
},
template: [
"<div>",
"Name : <strong>{{name}}</strong>; Change name:<input type='text' ng-model='name' /><br/>",
].join("")
};
});
JSFiddle Link
Please help me in updating controller value from directive inside this ngrepeat..
Basically the problem is the $scope.name inside the controller is not the same as you are passing to directive inside the ng-repeat element, because ng-repeat does create a child scope which is prototypically inherited from the parent scope while looping through rawdata object.
There are several ways to solve this problem.
If you wanted to solved this child and parent scope related issue just by using $parent annotation before name which will refers to parent scope.
Plunkr With $parent in directive
Cons:-
But after certain point $parent will make you crazy. Like suppose if you have two or three hierarchy of child scope it will become like $parent.$parent.$parent.name which looks very wiered.
In your case name is of primitive datatype, so while creating child scope the primitive datatypes values of parent scope aren't accessible inside the child scope. That is the reason why you were using $parent to indicates that name belongs to parent scope. You could overcome this problem just by following do annotation while declaring object. Which will help you to make parent scope property available inside the child by following prototypal inheritance.
HTML
<div class="directive" my-directive name="model.name"></div>
Code
$scope.model = {
name: 'HappyNewYear2016'
};
Plunkr with Dot Notation
You could solve this problem just by passing name value from the run function on ng-click="run(name)"
Html
<div ng-repeat="(k,v) in rawdata">
{{k}} {{v.key}} Name <strong>{{name}}</strong>
<div class="directive" my-directive name="name"></div>
<button ng-click="run(name)">See changes</button>
<br>
</div>
Code
$scope.run = function(name) {
alert(name);
}
You could use controllerAs syntax while declaring controller with its alias and the pass the controller name property by its alias.
Working Plunkr
It's all because of how prototypical inheritance works as both scopes directive and controller have same name for model. Child directive shadows the controller model.
Instead of storing controller model directly as variable use it with object.
$scope.data = {
name : 'HappyNewYear2016'
}
Then use it asdata.name to setup in ng-repeat. It will reflect it in parent as well.
I'm trying to build a directive in AngularJS that has a template which could contain other AngularJS directives. All of my directives require an "id" attribute, so I need to set the "id" on the directive inside the template. However, no matter how I do this, AngularJS keeps throwing this error:
Error: [$parse:syntax] Syntax Error: Token '{' invalid key at column 2 of the expression [{{field.id}}] starting at [{field.id}}].
http://errors.angularjs.org/1.4.6/$parse/syntax?p0=%7B&p1=invalid%20key&p2=2&p3=%7B%7Bfield.id%7D%7D&p4=%7Bfield.id%7D%7D
at angular.js:68
at Object.AST.throwError (angular.js:13010)
at Object.AST.object (angular.js:12997)
at Object.AST.primary (angular.js:12905)
at Object.AST.unary (angular.js:12893)
at Object.AST.multiplicative (angular.js:12880)
at Object.AST.additive (angular.js:12871)
at Object.AST.relational (angular.js:12862)
at Object.AST.equality (angular.js:12853)
at Object.AST.logicalAND (angular.js:12845)
I know that AngularJS is fine doing something like this: <div id="{{field.id}}">[...]</div>. It ends up being rendered correctly, with "{{field.id}}" replaced with the actual value of field.id. However once I try to apply my directive to that div, or use the directive as an element itself, AngularJS balks. I've tried all of the following and all result either in the error above or with the directive's ID set to "field.id" rather than the value of "field.id":
<!-- result in error shown above -->
<mydirective id="{{field.id}}"></mydirective>
<div mydirective id="{{field.id}}"></div>
<div class="mydirective" id="{{field.id}}"></div>
<mydirective ng-attr-id="{{field.id}}"></mydirective>
<div mydirective ng-attr-id="{{field.id}}"></div>
<div class="mydirective" ng-attr-id="{{field.id}}"></div>
<!-- result in id set to "field.id" -->
<mydirective id="field.id"></mydirective>
<div mydirective id="field.id"></div>
<div class="mydirective" id="field.id"></div>
<mydirective ng-attr-id="field.id"></mydirective>
<div mydirective ng-attr-id="field.id"></div>
<div class="mydirective" ng-attr-id="field.id"></div>
In case it helps, the general layout of the directive with the template looks like this:
<div ng-repeat="field in fields" ng-show="field.visible">
<!-- some other stuff -->
<mydirective ng-if="field.type == 'foobar'" id="{{field.id}}"></mydirective>
<!-- some other stuff -->
</div>
I'm seeing an identical issue with another attribute on the directive as well, so it's not limited to just the 'id' attribute.
Shortened version of the directive throwing the error:
var application = angular.module('application', []);
application = application.directive('mydirective', ['$http', function($http){
return {
restrict: 'AEC',
scope:{
mydirectiveId: '=id',
id : '#',
// a few other attributes
},
templateUrl: 'mydirective.html',
controller: function ($scope, $element){
if($scope.id === undefined){
console.error("The 'id' on mydirective is missing!");
}
// more logic... sorry can't post this
}
};
}]);
Can you show your directives code,if the name of your directive is myDirective,it should be my-Directive in the html.Also make sure you are using the restrict option on the correct element,attribute
I managed to figure this out. I'm not exactly sure why, but AngularJS was having a problem with the isolated scope on "mydirective". When I removed the mydirectiveId: '=id' attribute from the scope declaration, it started working again as expected.
Working HTML Template for parent directive:
<div ng-repeat="field in fields" ng-show="field.visible">
<!-- some other stuff -->
<mydirective ng-if="field.type == 'foobar'" id="{{field.id}}"></mydirective>
<!-- some other stuff -->
</div>
Working directive code for "mydirective":
application = application.directive('mydirective', ['$http', function($http){
return {
restrict: 'AEC',
scope:{
// mydirectiveId: '=id', << removed this line, it was the problem
id : '#',
// a few other attributes
},
templateUrl: 'mydirective.html',
controller: function ($scope, $element){
if($scope.id === undefined){
console.error("The 'id' on mydirective is missing!");
}
// more logic
}
};
}]);
Having another problem with figuring out Angular Typescript; this time when it comes to directives with controllers. Trying to pass an object from a page to a directive and then use that object in the controller of the directive. Maybe this isn't the correct approach, but it seems to make sense to me; just can't figure out how to access the object in the controller.
HTML from page:
<div>
<section>
On View: {{ee.obj.name}}
<image-upload obj="ee.obj"></image-upload>
</section>
</div>
Directive template:
<div>
On directive: {{obj.name}}
On controller: {{iuc.obj.name}}
<div class="row">
<div class="col-md-4 text-primary h4">
Add Images
</div>
</div>
<div class="row">
<div class="col-md-3">
<input type="file" multiple ng-model="iuc.imageUploads" ng-change="iuc.uploadImages()" />
</div>
</div>
<div class="row">
<div class="col-md-3 dropzone"></div>
</div>
</div>
Directive typescript:
/// <reference path="../../../scripts/_all.ts" />
module ObjConfig {
'use strict'
export class ImageUpload implements ng.IDirective {
static instance(): ng.IDirective {
return new ImageUpload();
}
restrict = 'E';
replace = true;
templateUrl = '../../../../App/AppConfig/Views/Directives/ImageUpload.html';
scope = {
obj: '='
};
controller = imageUploadCtrl;
controllerAs = 'iuc';
}
export class imageUploadCtrl {
obj: OBJBase;
imageUploads: OBJImage[];
constructor() {
}
uploadImages() {
//THIS IS WHERE I WANT TO ACCESS OBJ
//this.imageUploads.forEach((iu) => { this.obj.images.push(iu); });
}
}
angular.module('ObjConfig').directive('imageUpload', ImageUpload.instance);
}
When I use "this.obj" in the method, it comes back as undefined so obviously the controller "obj" doesn't get automatically wired up to the directive "obj". The ee.obj.name on the page shows value, the obj.name at the top of the directive template shows value, but the iuc.obj.name does not show value. So I've been trying to find a way to link the directive obj to the controller obj and I've tried using a link function to use ng.IAttributes, but that doesn't give me the object; it gives me ee.obj.
Any help would be greatly appreciated.
You should be able to accomplish what you are trying to do using bindToController: true.
This feature is documented in the $compile documentation, so it's not easy to locate, but it does what you want.
When an isolate scope is used for a component (see above), and controllerAs is used, bindToController: true will allow a component to have its properties bound to the controller, rather than to scope. When the controller is instantiated, the initial values of the isolate scope bindings are already available.
Say I have the following directive called foo:
<div>
<label>Enter foo: </label>
<input ng-model="myModel"/>
</div>
And I use it like so:
<foo></foo>
<button>Add foo: </button>
What I am trying to do is dynamically add the foo directive on each button click and be able to have access to the new model variable that was created in the corresponding controller for this page.
Can this be done using angularJS?
First of all, if you plan to re-use <foo>, then you should create an isolated scope:
.directive("foo", function(){
return {
restrict: "E",
scope: {
data: "="
},
template: "<div><label>Enter foo: </label><input ng-model='data'/></div>"
}
});
There is no difference between creating a custom directive or other tags. Without knowing too much about what you're doing, I could suggest the following:
app.controller("MainCtrl", function($scope)){
$scope.fooModels = [];
$scope.addFoo = function(){
$scope.fooModels.push(new FooModel());
};
}
FooModel() here is just a placehold for whatever the data model you need to represent foo data. You could also just do: $scope.fooModels.push({});.
Then in the view, simply ng-repeat your fooModels:
<div ng-repeat="fooModel in fooModels">
<foo data="fooModel.data"></foo>
</div>
<button ng-click="addFoo()">Add Foo</button>
Here's a plunker to play with.