Two way binding is not working with angular js - angularjs

I have the html code like this:
<div ng-controller="MainCtrl">
<tr data-ng-repeat="element in awesomeThings">
<div ng-if="$even">
<td ng-click="getServiceDetails(element)">
<a href="#">
{{element['serviceDetail']['name']}}
</a>
</td>
</div>
</tr>
//after some html
<span >{{publicName}}</span>
</div>
My controller looks like this:
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = {"serviceDetail":{"name":"batman"}}
$scope.getServiceDetails = function(serviceDetails)
{
console.log('Called')
$scope.publicName = serviceDetails.name
}
});
After clicking on the td tag, the span text are not changing! Even though me changing the publicName in the current scope!
Where I'm making the mistake?

You don't have a name property in your $scope.awesomeThings array.
Here I added some animals for you.
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = [
{ name: "Dog" },
{ name: "Cat" }
];
$scope.getServiceDetails = function(serviceDetails)
{
console.log('Called')
$scope.publicName = serviceDetails.name
}
});
Edit:
I put together a JSFiddle that solves your edit.
http://jsfiddle.net/HB7LU/7191/

$scope.awesomeThings is an array of string so element does not have a 'name' property.
You also have a missing ; after your console.log which may be stopping the code from running.
It may help you to log what the object is.
<div ng-controller="MainCtrl">
<tr data-ng-repeat="element in awesomeThings">
<div ng-if="$even">
<td ng-click="getServiceDetails(element)">
<a href="#">
{{element.name}}
</a>
</td>
</div>
</tr>
//after some html
<span >{{publicName}}</span>
</div>
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = {"serviceDetail":{"name":"batman"}};
$scope.getServiceDetails = function(serviceDetails)
{
console.log(serviceDetails);
$scope.publicName = serviceDetails.name;
}
});

Your main issue is this:
$scope.publicName = serviceDetails.name
It needs to be
$scope.publicName = serviceDetails;
$scope.awesomeThings is an array of strings, not objects. You're ng-repeating through the string array and passing the string to your getServiceDetails method, so 'serviceDetails' is just a string.
As an unrelated warning, I see you're using tr inside a div. The tr should be inside a table, thead, or tbody.

Related

Switch between displayed data

I've started looking at AngularJS a few hours ago so I'm settling into how things work. As part of a basic example, I'm trying to figure out how I switch between displayed data in a table.
At the moment, I've got the following as my basic app;
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
</head>
<body>
<div ng-app="applicationMain" ng-controller="controllers.app.main">
<table>
<tr ng-repeat="item in items">
<button>Toggle</button>
<td>{{item.name}}<td>
</tr>
</table>
</div>
</body>
<script>
var controllers = {
app : {
main : function($scope){
var s = $scope;
s.items = [
{
name : "Pizza",
price : 100
},
{
name : "Burger",
price : 45
},
{
name : "Kebab",
price : 85
}
];
}
}
}
var app = angular.module("applicationMain", []);
app.controller('controllers.app.main', controllers.app.main);
</script>
</html>
Fairly simple. Scoped array of objects with name and price fields, where the name of each is displayed in a table using ng-repeat
What I'd like to do is when I click the Toggle button, it switches between displaying the data of item.name to displaying data of item.price.
Is this something that can be done within the angular expression of the <TD> tags, or would a function be the way to go?
If I was using regular old JS for example, I might do something like this;
var activeField = item.name;
if (activeField == item.name){
activeField = item.price
} else {
activeField = item.name
}
However, I tried something similar by creating a 'switchField' function in my controller, but Angular reports that 'item is not defined' (essentially a scoping issue) even when defining it at $scope.item.price and $scope.item.name respectively.
You can do something like this, using ngClick, ngShow and ngHide:
<table>
<tr ng-repeat="item in items">
<button ng-click="toggleIt()">Toggle</button>
<td ng-show="toggle">{{item.name}}<td>
<td ng-hide="toggle">{{item.price}}<td>
</tr>
</table>
And add this to the controller:
s.toggle = true;
s.toggleIt = function() {
s.toggle = !s.toggle;
}

How to go from one <a> to another <a> in angularJs

CONTROLLER
$scope.employee = {};
$scope.setEmployee = function (employee) {
$scope.employeeId = employee.id;
$scope.employee = employee;
a($scope.employeeId);
};
var a = function () {
$scope.meetingTypes = MeetingService.findByEmployee({
'employeeId': $scope.employeeId
}, function () {
angular.forEach($scope.meetingTypes, function (meetingType) {
$scope.meetings = MeetingService.findByMeetingType(meetingType);
});
});
};
TEMPLATE
<tr>
<td>
<a ng-repeat="meetingType in meetingTypes">
- {{meetingType}}
</a>
<a ng-repeat="meeting in meetings">
- {{meeting}}
</a>
</td>
</tr>
Here I want to open second <a> tag on click of first <a> tag
The view should like tree view
LIKE :
- meeting_type
- meeting 1
- meeting 2
all services are declared in my .factory
Here I am getting meeting Type properly but i want to open list of meetings on click of meetingType <a> tag but i am not getting meetings here,
Is ng-href is helpfull here ?
Here is a some sample code which I think demonstrates what you want to acheive -
<table ng-app="myApp" ng-controller="TestCtrl">
<tr>
<td>Get Meetings</td>
</tr>
<tr>
<td>
<ul>
<li ng-repeat="meetingType in meetingTypes track by $index">
- {{meetingType.typeName}}
<ul ng-show="showMeetings && meetingType.meetings.length>0">
<li ng-repeat="meeting in meetingType.meetings track by $index">
<a>- {{meeting}}</a>
</li>
</ul>
</li>
</ul>
</td>
</tr>
</table>
javascripts -
'user strict';
angular.module('myApp', [])
.controller('TestCtrl', function($scope) {
$scope.employee = {};
$scope.meetingTypes = {};
$scope.setEmployee = function(employee) {
$scope.employeeId = 1;
//$scope.employee = {};
a($scope.employeeId);
};
var a = function() {
// your service should return this json
$scope.meetingTypes = [{
typeName: 'abc',
meetings: ['meeting1', 'meeting2', 'meeting3']
}, {
typeName: 'def',
meetings: ['meeting4', 'meeting5', 'meeting6']
}, {
typeName: 'ghi',
meetings: ['meeting7', 'meeting8', 'meeting8']
}];
};
});
jsfiddle

Angular update object in array

I wanna update an object within an objects array. Is there another possibility than iterating over all items and update the one which is matching? Current code looks like the following:
angular.module('app').controller('MyController', function($scope) {
$scope.object = {
name: 'test',
objects: [
{id: 1, name: 'test1'},
{id: 2, name: 'test2'}
]
};
$scope.update = function(id, data) {
var objects = $scope.object.objects;
for (var i = 0; i < objects.length; i++) {
if (objects[i].id === id) {
objects[i] = data;
break;
}
}
}
});
There are several ways to do that. Your situation is not very clear.
-> You can pass index instead of id. Then, your update function will be like:
$scope.update = function(index, data) {
$scope.object.objects[index] = data;
};
-> You can use ng-repeat on your view and bind object properties to input elements.
<div ng-repeat="item in object.objects">
ID: <input ng-model="item.id" /> <br/>
Name: <input ng-model="item.name" /> <br/>
</div>
Filters that help in finding the element from the array, can also be used to update the element in the array directly.
In the code below [0] --> is the object accessed directly.
Plunker Demo
$filter('filter')($scope.model, {firstName: selected})[0]
Pass the item to your update method. Take a look at sample bellow.
function MyCtrl($scope) {
$scope.items =
[
{name: 'obj1', info: {text: 'some extra info for obj1', show: true}},
{name: 'obj2', info: {text: 'some extra info for obj2', show: false}},
];
$scope.updateName = function(item, newName){
item.name = newName;
}
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app>
<table ng-controller="MyCtrl" class="table table-hover table-striped">
<tr ng-repeat="x in items">
<td> {{ x.name }}</td>
<td>
Update
<div ng-show="showUpdate" ><input type="text" ng-model="someNewName"> <input type="button" value="update" ng-click="updateName(x, someNewName); showUpdate = false;"></div>
</td>
</tr>
</table>
</body>
Going off your plunker, I would do this:
Change
Edit
to be
Edit
Then use the array index within your $scope.selectSubObject method to directly access your desired element. Something like this:
$scope.selectSubObject = function(idx) {
$scope.selectedSubObject = angular.copy(
$scope.selectedMainObject.subObjects[idx]
);
};
If however, you only have the id to go off of, then you can use the angular filterService to filter on the id that you want. But this will still do a loop and iterate over the array in the background.
See angularjs documentation for ngrepeat to see the variables that it exposes.

How to use a variable inside the ng-repeat?

I'm using the ng-repeat to list all the products, and I want to print out a star symbol x times depending on the product.rating. So, the code looks like following:
<p class="bs-rating"><i class="fa fa-star" ng-repeat="i in getRating({{ product.rating }}) track by $index"></i></p>
However, it parsed the product.rating as a String: Error: [$parse:syntax] http://errors.angularjs.org/1.3.0-beta.8/$parse/syntax?p0=product.rating&p1=is
I have tried to remove the curly brackets, {{ }}:
<p class="bs-rating"><i class="fa fa-star" ng-repeat="i in getRating(product.rating) track by $index"></i></p>
It gave me undefined. My getRating() is declared as following:
$scope.getRating = function(rating){
return new Array(parseInt(rating));
}
Could you help me figure it out how to pass a variable to ng tag?
The problem is on getRating function ie on generating the array.
I have developed an alternative solution on this link rating using ng-repeat #jsfiddle
<div ng-app="myApp" ng-controller="myCtrl">
<ol>
<li ng-repeat="product in products">
{{product.name}}
(
<span style="font-weight:bold" ng-repeat="i in
getRating(product.rating)">
x
</span>
)
</li>
</ol>
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope){
$scope.products = [
{name : "product1", rating:3},
{name : "product2", rating:5},
{name : "product3", rating:1}
];
$scope.getRating = function(rating){
var ratingArray = [];
for (var i = 1; i <= rating; i++) {
ratingArray.push(i);
}
return ratingArray;
};
});
Hopefully it will help.
Cheers

update fields in ngRepeat based on another field in same index

I want to be able to populate a text input field inside an ng-repeat loop with the value of another field inside that same loops index when I click a button.
JSFiddle of what I have so far: http://jsfiddle.net/3FKMx/
When the Copy Names button is clicked I want each text box to be populated with the same value that's in the array. Currently it populates them all with the value of the last item in the array.
Controller:
var app = angular.module('myApp', []);
function someController($scope) {
$scope.names = ["name1","name2","name3"];
$scope.copyNames = function() {
angular.forEach($scope.names,
function (value){
$scope.newName = value;
}
);
};
}
Template:
<div ng-controller="someController">
<button class="btn btn-primary" ng-click="copyNames()">Copy Names</button>
<table>
<tr ng-repeat="name in names">
<td>{{name}}</td>
// I want to populate this input with {{ name }} when I click the button above.
<td><input type="text" ng-model="newName"/></td>
</tr>
</table>
</div>
Solution 1
With an updated data structure it's a bit nicer for looping through.
Solution 2
Create a new array to store the values. Set them by key and look them up by key in your curly braces.
html
<div ng-controller="someController">
<button class="btn btn-primary" ng-click="copyNames()">Copy Names</button>
<table>
<tr ng-repeat="name in names">
<td>{{name}}</td>
<td><input type="text" ng-model="models[name]"/></td>
</tr>
</table>
</div>
JavaScript
var app = angular.module('myApp', []);
function someController($scope) {
$scope.names = ["name1","name2","name3"];
$scope.models = {};
$scope.copyNames = function() {
angular.forEach($scope.names,
function (value, key) {
$scope.models[value] = value;
}
);
};
}
DEMO (updated your fiddle) is what you are looking for?
Tried using an object to hold the label and model:
$scope.names = [{label: "name1", model: ''},
{label: "name2", model: ''},
{label: "name3", model: ''}];
//Also using jQuery.each to break from the loop
//once we know which value to copy
$scope.copyNames = function() {
$.each($scope.names,
function (i, value){
if(value.model) {
angular.forEach($scope.names, function(name){
name.model = value.model;
});
//Break the loop if done copying
return false;
}
}
);
};
Note: jQuery is used as an external library which will be available in angular as is.

Resources