AngularJs DOM element inside ng-repeat - javascript

I have my ng-repeat in div tag:
<div ng-repeat="x in names">
<h1>{{x.product}}</h1>
<h2>{{x.brand}}</h2>
<h3>{{x.description}}</h3>
<h4>{{x.sum}}</h4>
<h5>{{x.productid}}</h5>
</div>
<button ng-click="addToCart()">Add To Cart</button>
And my AngularJS script:
$scope.addToCart = function () {
$scope.productId = $scope.x.productid;
$http.post("api/shoppingCart/" + $scope.productId);
}
My problem is what I can't access/get {{x.productid}} value for my $scope.productid.

You can pass the item reference(x) - or the production id x.productid to the addToCart method
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.names = [{
product: 'a',
productid: 1
}, {
product: 'b',
productid: 2
}, {
product: 'c',
productid: 3
}, {
product: 'd',
productid: 4
}];
$scope.addToCart = function(x) {
$scope.productId = x.productid;
$http.post("api/shoppingCart/" + $scope.productId);
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="my-app" ng-controller="AppController">
<div ng-repeat="x in names">
<h1>{{x.product}}</h1>
<h2>{{x.brand}}</h2>
<h3>{{x.description}}</h3>
<h4>{{x.sum}}</h4>
<h5>{{x.productid}}</h5>
<button ng-click="addToCart(x)">Add To Cart</button>
</div>
<p>productId: {{productId}}</p>
</div>

change button like this <button ng-click="addToCart(x.productid)">Add To Cart</button> and your function is like
`$scope.addToCart = function (productid) {
$http.post("api/shoppingCart/" + productid);
}`

I think the best possibility for you to make it work is to add the button in the ng-repeat:
HTML:
<div ng-repeat="x in names">
<h1>{{x.product}}</h1>
<h2>{{x.brand}}</h2>
<h3>{{x.description}}</h3>
<h4>{{x.sum}}</h4>
<h5>{{x.productid}}</h5>
<button ng-click="addToCart(x.productid)">Add To Cart</button>
</div>
JS:
$scope.addToCart = function(id) {
$scope.productId = id;
$http.post("api/shoppingCart/" + $scope.productId);
};

Your addToCart is out of
<div ng-repeat="x in names">
<h1>{{x.product}}</h1>
<h2>{{x.brand}}</h2>
<h3>{{x.description}}</h3>
<h4>{{x.sum}}</h4>
<h5>{{x.productid}}</h5>
<button ng-click="addToCart(x.productid)">Add To Cart</button>
</div>
in JS file
$scope.addToCart = function (pid) {
$http.post("api/shoppingCart/"+ pid);
}

ng-repeat creates new scopes for each iteration. In you case, the x is in one of the child scopes of your ng-repeat.
The only place where you have an access to this scope is inside your view, so what you can do is the following :
<button ng-click="addToCart({{x.productId}})">Add To Cart</button>
and modifying your controller like that :
$scope.addToCart = function (productId) {
//$scope.productId = $scope.x.productid;
$http.post("api/shoppingCart/" + productId);
}
You may be wondering why you have access to a parent scope inside the view, you can google angular prototypal inheritance for more info

You can pass productId as a function parameter and you can use ng-bind instead of {{}} that's give you better performance and not rendered unwanted expression in DOM. if you use {{}} some time you see {{x.product}} in DOM while loading.
in HTML:
<div ng-repeat="x in names">
<h1 ng-bind="x.product"></h1>
<h2 ng-bind="x.brand"></h2>
<h3 ng-bind="x.description"></h3>
<h4 ng-bind="x.sum"></h4>
<h5 ng-bind="x.productid"></h5>
<button ng-click="addToCart(x.productid)">Add To Cart</button>
</div>
in controller:
$scope.addToCart = function (productId) {
$http.post("api/shoppingCart/"+ productId);
}

Related

Why can't I print the value from input type using AngularJS?

Here is a very simple application that lets the user change his name. However, there is some bug in this code. Whenever the user writes something into input, the change is not reflected in the welcome header.
app.js
'use strict';
angular
.module('angularScopesBug', [])
.controller("WelcomeController", function ($scope) {
$scope.name = 'John Doe';
$scope.getName = function() {
return $scope.name;
};
})
.controller("EditingController", function($scope) {
$scope.editMode = false;
$scope.changeName = function() {
$scope.editMode = true;
};
$scope.closeEditor = function() {
$scope.editMode = false;
};
})
.directive("nameEditor", function () {
return {
template: 'Write your name: <input type="text" ng-model="name">'
};
});
index.html
<div ng-app="angularScopesBug" ng-controller="WelcomeController">
<h1>Hello, {{ getName() }}</h1>
<div ng-controller="EditingController">
<button ng-click="changeName()" ng-show="!editMode">Change your name</button>
<div ng-show="editMode">
<name-editor ng-show="editMode"></name-editor>
<button ng-click="closeEditor()" ng-show="editMode">Close name editor</button>
</div>
</div>
</div>
The header should change according to the input.
Always use an object in ng-model.
Primitives have no inheritance and the nested controller is using a child scope. When that child scope is created it gets the primitive name as value.
When it is an object the object is inherited so that updating property values will be reflected in all references to that object
angular
.module('angularScopesBug', [])
.controller("WelcomeController", function($scope) {
$scope.model = {
name: 'John Doe'
};
})
.controller("EditingController", function($scope) {
// simplified for clarity
})
.directive("nameEditor", function() {
return {
template: 'Write your name: <input type="text" ng-model="model.name">'
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" ></script>
<div ng-app="angularScopesBug" ng-controller="WelcomeController">
<h1>Hello, {{ model.name }}</h1>
<div ng-controller="EditingController">
<button ng-click="editMode = true" ng-show="!editMode">Change your name</button>
<div ng-show="editMode">
<name-editor ng-show="editMode"></name-editor>
<button ng-click="editMode = false" ng-show="editMode">Close name editor</button>
</div>
</div>
</div>
Your two controllers have different $scope values. Since the editor is inside the EditingController $scope, it is changing a .name value in the lower scope, not in the higher WelcomeController $scope.
Try giving yourself a parent method to modify the value;
$scope.changeName = function(str) {
$scope.name = str;
};
And then calling that method with the new name from the child.

Isolated Scope not working

Here is my custom directive code
(function () {
var app = angular.module('CustDirMod', []);
var custdirCtrl = function ($scope) {
$scope.Person = {
Name: 'Jagan868',
address: {
street: '10 Donwstreet',
city: 'North Avenue',
state: 'Los Angeles'
},
friends: [
'Friend1',
'Friend2',
'Friend3'
]
};
};
var custDirectivewithBinding = function () {
return {
templateUrl: "Friends.html",
restrict: "E",
controller: function ($scope) {
$scope.KnightMe = function (Person) {
Person.rank = "Knight";
}
}
}
};
app.controller('CustDirCtrl', custdirCtrl);
app.directive("custDirectiveBinding", custDirectivewithBinding);
})();
and here is my template html
<div class="panel panel-primary">
<div class="panel-heading">
{{ Person.Name }}
</div>
<div class="panel-body">
<div ng-show='!!Person.address'>
<h4>Address :
</h4>
{{Person.address.street}}
<br />
{{Person.address.city}}
<br />
{{Person.address.state}}
</div>
<h4>Friends :</h4>
<br />
<ul>
<li ng-repeat='friend in Person.friends'>
{{friend}}
</li>
</ul>
<div ng-show="!!Person.rank">
Rank : {{Person.rank}}
</div>
<button ng-show="!Person.rank" class="btn btn-success" ng-click="KnightMe(Person)">Knight Me</button>
</div>
</div>
Now the following final html page where i'm using the above custom directive
<!DOCTYPE html>
<html ng-app="CustDirMod">
<head>
<title>Simple Directives - Angularjs</title>
<script src="Scripts/jquery-3.1.1.js"></script>
<link href="Content/bootstrap.css" rel="stylesheet" />
<script src="Scripts/bootstrap.js"></script>
<script src="Scripts/angular-1.5.8.js"></script>
<script src="Scripts/CustomDirective.js"></script>
</head>
<body ng-controller="CustDirCtrl" class="container" style="padding-top:30px;">
<cust-directive-binding></cust-directive-binding><br /><br />
</body>
</html>
Now i tried to add isolated scope in my custom directive as follows
var custDirectivewithBinding = function () {
return {
templateUrl : "Friends.html",
restrict: "E",
scope: {
userdata: "="
},
controller: function($scope){
$scope.KnightMe = function (Person) {
Person.rank = "Knight";
}
}
}
};
and then in the html page as follows
<body ng-controller="CustDirCtrl" class="container" style="padding-top:30px;">
<cust-directive-binding userdata="Person"></cust-directive-binding><br /><br />
</body>
After adding the isolated scope named as 'userdata' i'm not getting any data in UI. But if i remove that 'userdata' isolated scope from both js & html file its working fine. How to resolve this issue.
P.S: I don't want name the isolated scope local property name same as "Person". I just want it to be something different so that i can distinguish easily.
You don't have a scope property Person in the directive , you renamed it to userdata when you created the isolated scope.
You either need to change the template to now use userdata instead of Person or change the name of userdata to Person so the template will work
scope: {
userdata: "="
}
// in view
{{ userdata.Name}}
Or
<cust-directive-binding Person="Person">
scope: {
Person: "="
}
// in view
{{ Person.Name}}
Because now inside your directive template data will be available with isolated scope variable userdata. To fix the issue you could use userdata instead of Person every where on template. But instead of doing that I'd suggest you to use alias on isolated scope like Person: "=userdata". Where it says userdata will be attribute inside directive data will be available with Person name.
scope: {
Person: "=userdata"
},

Angularjs directive link call function in ng-click

My directive works fine, but I'd like to use it in ng-click However, the function inside link can't be triggered.
http://jsfiddle.net/ovzyro1f/
<div ng-app="editer" ng-controller="myCtrl" class="container">
<div class="parents">
<div ng-repeat="item in items" class="wrap" sibs>
<span>{{item.name}}</span>
<button ng-click="">click</button>
</div>
</div>
</div>
JS
function myCtrl($scope) {
$scope.editedItem = null;
$scope.items = [{
name: "item #1",
thing: "thing 1"
}, {
name: "item #2",
thing: "thing 2"
}, {
name: "item #3",
thing: "thing 3"
}];
$scope.show = false; //ignore this line
}
var editer = angular.module('editer', []);
editer.directive('sibs', function() {
return {
link: function(scope, element, attrs) {
element.bind('click', function() {
element.parent().children().addClass('unclicked');
element.removeClass('unclicked');
})
scope.myClick = function() {
element.parent().children().addClass('unclicked');
element.removeClass('unclicked');
}
},
}
});
I'd like to call the function in ng-click please see this one http://jsfiddle.net/ovzyro1f/2/ to remove sib from div ng-repeat="item in items" class="wrap"
<button ng-click="myClick()">click</button>
You should avoid to manipulate the DOM like we do in jQuery.
In Angular we think differently: it's the data which transforms automatically the DOM when the data changes (https://docs.angularjs.org/guide/databinding). Most of the time you never have to make the changes manually.
In doing so, you generally don't need to use the link function. You can have a controller (like in your example) or a directive with a controller (https://docs.angularjs.org/guide/directive).
Finally I just modified a little bit your controller and your template.
HTML
<div ng-app="editer" ng-controller="myCtrl" class="container">
<div class="parents">
<div ng-repeat="item in items" class="wrap" sibs>
<span ng-class="{ unclicked: !item.selected }">{{ item.name }}</span>
<button ng-click="selectItem(item)">click</button>
</div>
</div>
</div>
JS
function myCtrl($scope) {
$scope.items = [...];
$scope.selectItem = function (item) {
// reset all the items
$scope.items.forEach(function (i) {
i.selected = false;
});
// set the new selected item
item.selected = true;
}
}

Unable to ng-repeat directives in angularjs

I am new to angularjs. I want to dynamically add directives to a div based the titles from controller.. Below is what i tried...
Below is the directives and factory i used
QtTemplate.directive("shortanswer",function()
{
return{
restrict:"A",
templateUrl:'assets/directives/shortAnswer.html'
}
})
Template.factory("questionList",function()
{
var questionList={};
questionList.testid="1";
questionList.name="Maths";
questionList.Questions =
[
{"title":"truefalse"},
{"title":"shortanswer"}
]
return questionList;
})
Template.controller("questionControl",['$scope','questionList',function($scope,questionList)
{
$scope.name = questionList.name;
$scope.id = questionList.testid;
$scope.Questions = questionList.Questions;
}])
Template.directive('dynamicDirective',function($compile)
{
return {
restrict: 'A',scope:{},
replace: false,
terminal: true,
priority: 1000,
link:function(scope,element,attrs)
{
element.attr(scope.$eval(attrs.dynamicDirective),"");
element.removeAttr("dynamic-directive"); //remove the attribute to avoid indefinite loop
element.removeAttr("data-dynamic-directive");
$compile(element)(scope);
}
};
});
QtTemplate.directive("shortanswer",function()
{
return{
restrict:"A",
templateUrl:'assets/directives/shortAnswer.html'
}
})
Below is how i use ng-repeat
<div ng-repeat="Questions in Questions" >
<div dynamicDirective="{{Questions.title}}" ></div>
</div>
This is not working
use-kebab-case-in-html
<div ng-repeat="Question in Questions" >
<div dynamic-directive="{{Question.title}}" ></div>
</div>
You need to write dynamic-directive instead of dynamicDirective in your HTML. Camelcase in Javascript needs to be written as snakecase kebab-case in HTML.
Here you are:
<div ng-repeat="Question in Questions" >
<div dynamicDirective="{{Question.title}}" ></div>
</div>
Hope this helps.

ng-repeat dynamic array name

Is it possible to achieve dynamic array name, something like friends+$index. For example:
ng-repeat="friend in {{'friends'+$index}}"
The aim is to loop through different arrays: friends1 & friends2.
I tried everything, any combination, but without success. I also never came across to appropriate answers.
Thanks in advance.
You can do something like this.
http://jsfiddle.net/jigardafda/gw7f1qq0/1/
HTML
<div ng-app="myapp">
<div ng-controller="MyCtrl">
<div ng-repeat="(name, value) in frndslist">
{{name}}
<div ng-repeat="item in value.list">
{{item}}
</div>
</div>
</div>
</div>
JS
var myApp = angular.module('myapp',[]);
myApp
.controller('MyCtrl', function ($scope, $rootScope) {
$scope.frndslist = {
'friend1': {
name: 'x1 frnd',
list: [
"1.some1",
"1.some2"
]
},
'friend2': {
name: 'x2 frnd',
list: [
"2.some1",
"2.some2"
]
}
};
});
Here's another solution:
The HTML:
<div ng-app="App" ng-controller="AppController as controller">
<ul ng-repeat="friend in friends[index]">
<li>{{friend}}</li>
</ul>
</div>
Javascript:
var application = angular.module("App",[]);
application.controller("AppController",function($scope){
friends1 =["Name1", "Name2", "Name3", "Name4"];
friends2 =["Name5", "Name6", "Name7"];
$scope.friends = new Array();
$scope.friends.push(friends1);
$scope.friends.push(friends2);
//.......
$scope.index = 0; // in this example it can be 0 or 1
});

Categories