Editing ng-repeat objects - javascript

How do you go about editing an array of objects bound to a table using ng-repeat ?
I have the following starting array.
var students = [{
"FName": "Tom",
"LName": "Wilcox"
}, {
"FName": "Kevin",
"LName": "Johnson"
}, {
"FName": "Annebelle",
"LName": "Smith"
}, {
"FName": "Kelly",
"LName": "Masters"
}, {
"FName": "Phillip",
"LName": "Smith"
}, ];
I then push two of the students onto a second array and add a new property called "Grade" like this:
var testTakers = [];
var s;
for (s = 0; s < students.length; s++) {
if (students[s].LName == "Smith") {
students[s].Grade = ""; // New Grade Property
testTakers.push(students[s]);
}
}
$scope.TestTakers = testTakers;
I add a new 'Grade' property to the two selected objects and bind to a table using ng-repeat. The Grade' property is bound to a textbox for editing.
<table class="table-striped">
<tbody>
<tr ng-repeat="student in TestTakers">
<td class="col-md-2">{{student.FName}}</td>
<td class="col-md-2">{{student.LName}}</td>
<td class="col-md-2">
<input type="text" size="2em" ng-bind="Grade" style="text-align:center" />
</td>
</tr>
</tbody>
When I enter the grades into the textboxes Angular is not persisting those values. My goal is to add grades to the two new student objects and then post them back up to the server.
A functioning Plunker sample is here. Thank you in advance for any assistance in helping me with this!

You need to use ng-model instead of ng-bind inorder to set up a 2-way binding with the user input on the textbox and the bound view model.
<input type="text" size="2em" ng-model="student.Grade" class="text-center" />
Plnkr
Side Note: Since you already have boostrap css loaded you can just use existing css rule text-center instead of inline style to specify style="text-align:center".

Related

adding ang removing row

I have a grid array of objects and it has default data from the database , now on the front end the data are being displayed on the table/grid and user can add row and delete row , when I add a row I only want to insert an empty object.
my issue is when I add a row duplicate ids are existing and when I delete only just a single row sometimes multiple rows are being deleted
What seem to be the issue of my implementation ? how do I delete and add rows without compromising the ids ? Thanks.
#grid data - from the database
gridTableData [
{
"id": 0,
"demos": "21 Est. Pop",
},
{
"id": 1,
"demos": "Households",
},
{
"id": 5,
"demos": "Avg HH Inc",
},
]
#add and delete row code
deleteRow(id: number) {
const filteredDemographics = this.gridTableData.filter(s => s.id !== id);
this.gridTableData = [...filteredDemographics];
}
addRow() {
this.gridTableData.push({id:this.gridTableData.length});
console.log("this.gridTableData" , this.gridTableData)
}
#html
<tbody *ngIf="gridTableData.length > 0">
<tr *ngFor="let row of gridTableData;let i = index" [ngClass]="{'row-is-editing':isRowEditing(i)}">
<td>
<button *ngIf="checkIfExistsOnDefaultGrid(row) === false" class="material-icons-outlined" mat-icon-button color="error"
(click)="deleteRow(row.id)">
<mat-icon>delete_outline</mat-icon>
</button>
</td>
</tr>
</tbody>
If you are adding with the row length and removing by index you might get some weird cases.
For example, if you add two entries in your snippet, you will have 2 rows with ID 5. Therefore, when you filter/delete, you would remove two entries.
If you want change the order, always use the index to remove or add.
If you want to use ID, make sure the ID will always be unique.
Here is a possible solution making the ID random
https://stackblitz.com/edit/angular-pebbqb?file=src/app/app.component.ts

List only one property of object array

I want an Angular list showing all the instances of one object property from an array of objects, and nothing more – for example, only the countries.
$scope.testSites = [
{ "site": "Testsite1", "country": "Country1", "customer": "Customer1"},
{ "site": "Testsite2", "country": "Country2", "customer": "Customer2"}
];
$scope.chosenCategory = 1;
$scope.categoryNames = ["site", "country", "customer"];
$scope.aspect = $scope.categoryNames[$scope.chosenCategory];
However, I want to use the above variable 'aspect' for choosing which property to show in the list. Something like {{x.country}}, though it works, is therefore not sufficient. I've tried this, but it returns an empty list:
<table border="1" class="list-group-item list-group-item-success">
<tr>
<th>{{aspect | capitalize}}</th>
</tr>
<tr ng-repeat="x in testSites | orderBy:myOrderBy">
<td>
{{x.aspect}}
</td>
</tr>
</table>
Is there something I can do?
You can do via {{ x[aspect] }} - [] bracket notation. It evaluates the expressoin and uses the result to find the property.
You can find Demo here

Using data from JSON files as references to data from other JSON files

I am trying to make a website for a tabletop game a friend of mine created, and I want to store all the data in JSON files and pull up the data in HTML files with Javascript. I want to, for example, store each class in a separate file, with its skill list (only listing the skill name and level learned in this file) included in the file, and a master list of all skills, their costs, and their descriptions in another file. Basically, I want to treat two or more JSON files like linked tables in a database.
In this example, this is what would be found in the class's file:
{
"name": "Class 1",
"skills": [
{
"name": "Skill 1",
"level": 1
},
{
"name": "Skill 2",
"level": 2
},
{
"name": "Skill 3",
"level": 3
}
]
}
And this is the master skill file:
{
"skills": [
{
"name": "Skill 1",
"desc": "This is the first skill.",
"cost": "1 MP"
},
{
"name": "Skill 2",
"desc": "This is the second skill.",
"cost": "2 HP"
},
{
"name": "Skill 3",
"desc": "This is the third skill.",
"cost": "3 Gold"
},
{
"name": "Skill 4",
"desc": "This is a skill from a different class.",
"cost": "All MP"
}
]
}
And I want the HTML file to output something like this, using these two separate JSON files:
<h1>Class 1</h1>
<table>
<tr>
<td>Skill 1</td>
<td>Level 1</td>
<td>1 MP</td>
<td>This is the first skill.</td>
</tr>
<tr>
<td>Skill 2</td>
<td>Level 2</td>
<td>2 HP</td>
<td>This is the second skill.</td>
</tr>
<tr>
<td>Skill 3</td>
<td>Level 3</td>
<td>3 Gold</td>
<td>This is the third skill.</td>
</tr>
</table>
Can this be done? And if so, how?
jsBin demo
// GET MASTER FILE
$.getJSON( "db/master.json", function( data ) {
var masterSkills = data.skills; // Store master Object
// Now that we've read the master data let's see how many
// (cause you're working with Arrays)
// of those skills has the Class 1 file
// GET Class 1 FILE
$.getJSON( "db/class.json", function( data ) {
// Collect Class 1 skills (3 of them) adding data from
// our stored masterSkills
var rows = []; // Array to create rows
$.each( data.skills, function( i, val ) { // 3 of them
rows.push( "<tr>"+
"<td>"+ val.name +"</td>"+
"<td>Level "+ val.level +"</td>"+
"<td>"+ masterSkills[i].cost +"</td>"+
"<td>"+ masterSkills[i].desc +"</td>"+
"</tr>" );
});
// Append collected data do some element ("body")
$('<h1/>',{html: data.name }).appendTo("body");
$( "<table/>", { html: rows.join("") }).appendTo("body");
});
});
The above is usable ONLY if the sequence of both files matches the array count,
otherwise if you want to be sure to get only the right data that matches the exact level (in the case your class file has stored data in a non-incremental way) you'll have to change a bit the JSON structure, to prevent unnecessary loops to find an exact "Level" match. One way would be (master file):
{
"skill1" : {
"foo":"bar"
},
"skill2" : {
"blu":"bla"
},
}
now, instead of searching trough all "name" properties you can directly target the desired level and extract the values.
http://api.jquery.com/jquery.getjson/
Please correct me if I misunderstood your question, but you'll want to do something like this:
Store your master json file in on the server, e.g. data.json.
Either store everything else in the same file, like so: {"classes": [ classes go here ]}, or each in a separate file, like class1.json, class2.json, etc.
Then, use js to pull the data from the files to your html page, like so:
$.getJSON('data.json', function (data) { // do this for all your files
// process your data here
});
Then, within the callbacks, use basic DOM manipulation to create your table, e.g. (a simplified example):
var html = $("<p>The skill's name: " + data["skills"][0]["name"]);
$("#yourtable").append(html);
EDIT: if you want to do this for each skill, it's as simple as
var skills = data["skills"];
$.each(skills, function (index) {
// do your DOM stuff here (skills[index] is your skill)
});
That will iterate over each skill, and do the same thing for each one.
EDIT 2: here is the full code you asked for.
// assume class data is stored in files called [classname].json
var classname = "yourclass", masterfile = "master.json";
// fetch data from the master file
$.getJSON(masterfile, function (masterData) {
// fetch data from your class file
$.getJSON(classname + ".json", function (classData) {
var skills = classData["skills"]
// iterate over each skill in the class
for(var i = 0; i < skills.length; i++) {
var skill = skills[i];
// iterate over each skill in the master file
for(var j = 0; j < masterData["skills"].length; j++) {
// check if the names of the skill in the class and the skill in the master file match
if(masterData["skills"][j][name] === skill["name"]) {
// the skill names match
var s = masterData["skills"][j];
// s is now your skill variable, where s["cost"] is the cost, et cetera
// now, do your DOM manipulation using the skill data
}
}
}
});
});

Angularjs - Filter does not filter one column but filters others

I have never used filters extensively in angularjs and I just saw a problem with one of my projects..
The filter that I apply to a table is filtering all columns except for the one that multiplies the values of two items in the repeater.
1. Is this meant to work this way?
2. Is there a way to filter the column that multiplies numbers or adds strings together?
Here is the plunker with a working (not working) example
http://plnkr.co/edit/pmCjQL39BWWowIAgj9hP?p=preview
I have a filter that I apply to ng-repeater...
<input type="text" ng-model="tableSearch">
And then in table..
<tr ng-repeat="items in tableData | filter:tableSearch">
<td> {{ items.qty }} </td>
<td> {{ items.price }} </td>
// hm.....
<td> {{ items.qty*items.price }} </td>
</tr>
Update
Thanks to guidance from #Chandermani below I resolved the issue writing a custom filter. Here is the updated plunk: http://plnkr.co/edit/pmCjQL39BWWowIAgj9hP?p=preview
$scope.tableFilter = function(item) {
for (key in item) {
var m = item[key].toString();
var s = (item.qty * item.price).toString();
if(
s.indexOf($scope.tableSearch) != -1 ||
m.indexOf($scope.tableSearch) != -1 ||
$scope.tableSearch == undefined
){
return true;
};
}
return false;
}
Then filter is used like this:
<tr ng-repeat="items in tableData | filter:tableFilter">
Filter work on model data, in your case this data
{
"id": 1,
"name": "Apples",
"price": 19.99,
"qty": 1
},
{
"id": 2,
"name": "Oranges",
"price": 29.99,
"qty": 1
},
The last column has been generated in html. You would have to write a custom filter function for supporting that or add the last column value also to your model.
For custom filter function you can do something like
$scope.tableFilter=function(item) {
//should return true for the item to show up.
}
see documentation for filter http://docs.angularjs.org/api/ng/filter/filter

How do I render X <option>s in a <select>using jQuery.tmpl?

I'm inserting rows in a <table> that are bound to a JSON object. A cell in the table contains a <select> that needs to contain the number of objects, so 7 objects would produce 7 <option>s, 1-7.
Can this be done in the template definition?
Edit: I've added sample data and markup. From this data, I would want to add 3 <option>s (1-3) to the DisplayOrder <select> and have the appropriate <option> selected for each <select>.
Example: http://jsfiddle.net/4SxTS/
var data = [{
"Id": 1,
"DisplayOrder": 1,
"LabelText": "Unit On-Line Status:"},
{
"Id": 2,
"DisplayOrder": 2,
"LabelText": "AGC Pct:"},
{
"Id": 3,
"DisplayOrder": 3,
"LabelText": "Main Steam Heat Rate
}];
<table border="1" cellpadding="0" cellspacing="0">
<thead><tr><th>Display Order</th><th>Label Text</th></tr></thead>
<tbody></tbody>
</table>
<script id="attributeTemplate" type="text/x-jquery-tmpl">
<tr>
<td><select name="DisplayOrder"></select></td>
<td><input type="text" name="LabelText" value="${LabelText}" /></td>
</tr>
</script>
I'm not sure exactly what you mean without some sample data and markup, but I think the main part of your question deals with looping through numbers and rendering an option tag for each number. You could do this by creating an array containing "N" elements and then using {{each}}, but I think that using a custom template tag works well here:
Define a {{for}} tag that iterates through numbers 0 to n:
$.extend(jQuery.tmpl.tag, {
'for': {
open: "for(var $i = 0; $i < $1; $i++) {",
close: "}"
}
});
Use the new tag in a template:
<script type="text/html" id="row-tmpl">
{{each Rows}}
<tr>
<td>${Title}</td>
<td>${Description}</td>
<td>
<select>
{{for $data.TotalObjects}}
<option>${$i}</option>
{{/for}}
</select>
</td>
</tr>
{{/each}}
</script>
Called with:
var rows = {
TotalObjects: 5,
Rows: [{
Title: 'Test Row',
Description: 'Test Row Description'
},
{
Title: 'Another Row',
Description: 'Another Row Description'
}]
};
Best demonstrated in a working example: http://jsfiddle.net/xgE3Y/
Your situation might be even simpler, but my answer should enable you to at least use a simple for loop in a template and act on each iteration's value.
Maybe something like this:
$(function () {
var thisSelectObjects = 8;
var thatSelectObjects = 2;
$.fn.setOptions = function (options) {
var settings = {
'selectNum': 1
};
return this.each(function () {
if (options) {
$.extend(settings, options);
}
for (i = 0; i < settings.selectNum; i++) {
$(this).append('<option>' + i + '<option/>');
}
});
};
$('#thisSelect').setOptions({ 'selectNum': thisSelectObjects });
$('#thatSelect').setOptions({ 'selectNum': thatSelectObjects });
});
Html:
<body>
<select id='thisSelect'></select>
<select id='thatSelect'></select>
</body>

Categories