Knockout Js template not displaying data - javascript

I have the following knockout js code, for some reason, the booking.text is not displaying, see how column 1 has no text.
Can anyone advice what I have done wrong and how this can be fixed?
You can see the running code in JS Fiddle here. http://jsfiddle.net/w3fxtdq8/18/
Below is the code I am using
var myViewModel = {
bookings: ko.observableArray([{
text: 'booking 1',
bookingId: 123
},
{
text: 'booking 2',
bookingId: 123
},
{
text: 'booking 3',
bookingId: 123
}
])
};
ko.applyBindings(myViewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<thead>
<th>Column 1</th>
<th>Column 2</th>
</thead>
<tbody data-bind="template: {name: 'booking-table-row-template', foreach: 'bookings', as: 'booking'}">
</tbody>
</table>
<script type="text/html" id="booking-table-row-template">
<tr>
<td data-bind="text: booking.text"></td>
<td>
Remove
</td>
</tr>
</script>

You shouldn't put quotes around a variable name. The clue is in how many rows got rendered - 8 (same as the number of letters in the word 'bookings') rather than 3 (size of your array).
You made bookings a string.
var myViewModel = {
bookings: ko.observableArray([{
text: 'booking 1',
bookingId: 123
},
{
text: 'booking 2',
bookingId: 123
},
{
text: 'booking 3',
bookingId: 123
}
])
};
ko.applyBindings(myViewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<thead>
<th>Column 1</th>
<th>Column 2</th>
</thead>
<tbody data-bind="template: {name: 'booking-table-row-template', foreach: bookings, as: 'booking'}">
</tbody>
</table>
<script type="text/html" id="booking-table-row-template">
<tr>
<td data-bind="text: booking.text"></td>
<td>
Remove
</td>
</tr>
</script>

Related

ERROR TypeError: Cannot read property 'name' of undefined when i try to add product

I try to make a basket as simply as possible, I try to add a product to my basket but I have an error but I cannot find my error.
thank you
html
<h2>Product</h2>
<div class="card" *ngFor="let product of productList">
<h1>{{product.name}}</h1>
<p class="price">{{product.price | currency: 'USD'}}</p>
<p><button (click)=add()>Add to Cart</button></p>
</div>
</div>
<div>
<h2>Total</h2>
<div class="card">
<table>
<thead>
<tr>
<th>product</th>
<th>price</th>
<th>Quantity</th>
<th>total</th>
</tr>
</thead>
<tbody *ngFor="let added of productArray">
<tr>
<td>{{added.name}}</td>
<td>{{added.price}}</td>
<td>x 10</td>
<td>45€</td>
ts.file
productList = [
{ name: 'Louis Vuis', price: 10 },
{ name: 'shubert helmet', price: 20 },
{ name: 'sport gloves', price: 30 }
];
productArray: any = [];
add(product) {
this.productArray.push(product);
}
In your template, you have to change (click)="add()" to (click)="add(product)"

knockout.js can I pass an an array of data to a template?

Working with Knockout templates, all of the examples seem to pass in single values to the template instead of array data. I have a template which will create some basic HTML, and then render a table using the data passed in to the template. Here is how it looks:
<script type="text/html" id="my-template">
<p>Here is the data</p>
[MORE HTML DATA HERE]
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Surname</th>
</tr>
</thead>
<tbody data-bind="foreach: [WHAT DO I PUT HERE???]">
<tr>
<td data-bind="text: Id"></td>
<td data-bind="text: FirstName"></td>
<td data-bind="text: Surname"></td>
</tr>
</tbody>
</table>
</script>
<div data-bind="template: { name: 'my-template', data: PersonArray1 }"></div>
<div data-bind="template: { name: 'my-template', data: PersonArray2 }"></div>
<div data-bind="template: { name: 'my-template', data: PersonArray3 }"></div>
The templates do support a foreach binding, but I don't think I can use that as I don't want the template HTML heading data marked [MORE HTML DATA HERE] repeated for every item in the array.
I want the foreach binding within the template as in my rough example above. Is there a way I can make this work? I think the answer is in the placeholder i have marked with [WHAT DO I PUT HERE???] above, but I don't know if there is a variable which holds top-level template data.
What you are looking for is the $data parameter which will give you each entry from the supplied array:
var myViewModel = {
PersonArray1 : [
{ Id: 1, FirstName: "Alice", Surname: "Bloggs" },
{ Id: 2, FirstName: "Bob", Surname: "Bloggs" },
{ Id: 3, FirstName: "Claire", Surname: "Bloggs" }
]
};
ko.applyBindings(myViewModel)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script type="text/html" id="my-template">
<p>Here is the data</p>
[MORE HTML DATA HERE]
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Surname</th>
</tr>
</thead>
<tbody data-bind="foreach: $data">
<tr>
<td data-bind="text: Id"></td>
<td data-bind="text: FirstName"></td>
<td data-bind="text: Surname"></td>
</tr>
</tbody>
</table>
</script>
<div data-bind="template: { name: 'my-template', data: PersonArray1 }"></div>
I found the answer from this link, and the solution was posted by the creator himself.
https://github.com/knockout/knockout/issues/246
The solution is supplied in this fiddle:
http://jsfiddle.net/b9WWF/
The part of interest is where you call your template, instead of supplying an object directly to the data attribute, you can supply data in named values as follows:
<div data-bind="template: { name: 'my-template', data: { people: PersonArray1 } }"></div>
<div data-bind="template: { name: 'my-template', data: { people: PersonArray2, displayAdmins: false } }"></div>
You then access the array in your template as follows (I'm using my code above as an example):
<tbody data-bind="foreach: people">

How to share rows between two tables on the same page

I want to do something like this:
As you can see they must be in the same html page and should transfer rows without refreshing the entire page again.
Someone can give me some help?
Here's a screen shot of the results:
Here's the important parts of the HTML:
<body ng-controller="MainCtrl">
<table border=1>
<thead>
<tr>
<th colspan="2">Table 1</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in table1">
<td><input type="checkbox" ng-model="item.checked"></td>
<td><span ng-bind="item.data"></span></td>
</tr>
</tbody>
</table>
<br>
<button ng-click="transferRight()">Transfer ></button>
<br>
<button ng-click="transferLeft()">< Transfer</button>
<br>
<br>
<table border=1>
<thead>
<tr>
<th colspan="2">Table 2</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in table2">
<td><input type="checkbox" ng-model="item.checked"></td>
<td><span ng-bind="item.data"></span></td>
</tr>
</tbody>
</table>
</body>
Here's the important parts of the javascript/angularjs:
app.controller('MainCtrl', function($scope, $filter) {
$scope.table1 = [
{checked:false, data:'Data 1'},
{checked:true, data:'Data 3'},
{checked:true, data:'Data 4'},
{checked:false, data:'Data 6'},
{checked:false, data:'Data 7'}];
$scope.table2 = [
{checked:false, data:'Data 2'},
{checked:false, data:'Data 5'}];
$scope.transferRight = function() {
angular.forEach($filter('filter')($scope.table1, {checked: true}), function(value) {
value.checked = false;
$scope.table2.unshift(value);
$scope.table1.splice($scope.table1.indexOf(value), 1);
});
};
$scope.transferLeft = function() {
angular.forEach($filter('filter')($scope.table2, {checked: true}), function(value) {
value.checked = false;
$scope.table1.unshift(value);
$scope.table2.splice($scope.table2.indexOf(value), 1);
});
};
});
Here's a link to a working Plunker, http://plnkr.co/edit/qoARS4mtp5CQQnf1kogA?p=preview
You could look at this code. It's completely made with Javascript and html.
It's called a picklist btw.
just use append() or appendTo()
$(".toRight").click(function () {
$("#table1 input:checked").closest("tr").appendTo("#table2");
});
Here full code

Generate html table using angular

I want to generate html table using angular.I have a json object and i used ng-repeat to add multiple rows. But my table structure is different.
I want to generate table structure like this:
<table>
<tr>
<td >ID</td>
<td>Sub</td>
</tr>
<tr>
<td rowspan="3">1</td>
<td>S1</td>
</tr>
<tr>
<td>S2</td>
</tr>
<tr>
<td>S3</td>
</tr>
</table>
--------------
ID | subjects
--------------
| S1
--------
1 | S2
--------
| S3
--------------
| S4
--------
2 | S5
--------
| S6
--------------
user:[
{id:1 ,
subjects:[
{id:1 , name:"eng"}
{id:2 , name:"phy"}
]
},
{ id:2 ,
subjects:[
{id:1 , name:"eng"}
{id:3 , name:"math"}
]
}
]
my angular code is:
<tr ng-repeat = "user in users">
<td>{{user.id}}</td>
<td>{{user.subject}}</td>
</tr>
I want to know how to generate table structure like above
You need to use ng-repeat-start and ng-repeat-end. For example:
var app = angular.module('MyApp', []);
app.controller('MyController', function ($scope) {
var users = [{
id: 1,
subjects: [{
id: 1,
name: "eng"
}, {
id: 2,
name: "phy"
}]
}, {
id: 2,
subjects: [{
id: 1,
name: "eng"
}, {
id: 3,
name: "math"
}]
}];
$scope.users = users;
});
table { border-collapse: collapse; }
td { border: 1px solid Black; }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<table ng-app="MyApp" ng-controller="MyController">
<thead>
<tr>
<td>ID</td>
<td>Subjects</td>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="user in users">
<td rowspan="{{user.subjects.length+1}}">{{user.id}}</td>
</tr>
<tr ng-repeat-end ng-repeat="subject in user.subjects">
<td>S{{subject.id}}</td>
</tr>
</tbody>
</table>
Also, working fiddle here: http://jsfiddle.net/donal/r51d5fw5/17/
Similar to the nested structure of your object, you can nest your ng-repeats like this...
<tr ng-repeat = "user in users">
<td>{{user.id}}</td>
<td ng-repeat="subject in user.subjects">{{subject.name}}</td>
</tr>
I split your JSON and push it into two $scope variable, like the below:
angular.forEach($scope.user, function(user) {
$scope.userDetails.push({
userId: user.id,
});
angular.forEach(user.subjects, function(subject) {
$scope.subjectDetails.push({
userId: user.id,
subjectName: subject.name
});
});
});
In the HTML, I am using filter to filter by user's id.
<table>
<thead>
<tr>
<th style="width: 50px">ID</th>
<th style="width: 75px">Subjects</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in userDetails">
<td><span ng-bind="user.userId"></span>
</td>
<td>
<table>
<tr ng-repeat="sub in subjectDetails | filter: {userId: user.userId}">
<td>
<div ng-bind="sub.subjectName"></div>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
This is also one of the way to achieve this.
Sample Plunker
Here, I'm assuming that you want each user in users (in your JSON object) in one table, so you can do something as follows:
<table ng-repeat="user in users">
<tr>
<td>{{user.id}}</td>
<td>Subjects</td>
</tr>
<tr ng-repeat="subject in user.subjects">
<td>{{subject.id}}</td>
<td>{{subject.name}}</td>
</tr>
</table>
Adjust the html accordingly based on your needs, but this is the basic idea :)
Hope this helps!
add users object in $scope.
$scope.users=[
{id:1 ,
subjects:[
{id:1 , name:"eng"}
{id:2 , name:"phy"}
]
},
{ id:2 ,
subjects:[
{id:1 , name:"eng"}
{id:3 , name:"math"}
]
}
]
Here is the html.
<table border="1">
<tr>
<th> ID </th>
<th> subjects </th>
</tr>
<tr ng-repeat="user in users">
<td>{{user.id}}</td>
<td><table>
<tr ng-repeat="subject in user.subjects">
<td>{{subject.name}}</td>
</tr>
</table></td>
</tr>
</table>
Here is the plunker

angular ng-repeat inside of ng-repeat not working in table

I have the following
<tbody ng-repeat="history in orderHistory">
<tr>
<td>{{history.reference_code}}</td>
<div ng-repeat="items in history.orderedItems">
<td>{{items.product_description}}</td>
<td>{{items.quantity}}</td>
</div>
<td>
</tr>
</tbody>
it seems that the second ng-repeat is not working and {{items.quantity}} or items . anything does not end up showing.
any ideas?
When i just test it out like so it works
<div ng-repeat="history in orderHistory">
<div ng-repeat="items in history.orderedItems">
{{items.product_description}}
</div>
</div>
but i really need it inside the table
I tried the following:
<tbody>
<tr ng-repeat="history in orderHistory">
<td>{{history.reference_code}}</td>
<div ng-repeat="items in history.orderedItems">
<td>{{items.product_description}}</td>
<td>{{items.quantity}}</td>
</div>
<td>
</tr>
</tbody>
and still does not work
UPDATED Answer
http://plnkr.co/edit/x0ZxWSy6JN3fo961NbQX?p=preview
The following should get you going.
<table ng-controller="myCtrl">
<tbody>
<tr ng-repeat="history in orderHistory">
<td>{{history.reference_code}}</td>
<td ng-repeat-start="items in history.orderedItems">
{{items.product_description}}<//td>
<td ng-repeat-end>{{items.quantity}}</td>
</tr>
</tbody>
</table>
OLD ANSWER -----
Kept previous answer is kept for historical reasons due to comments.
The problem is tbody - not supposed to be repeated. I had a similar problem with <p> just like what you see in here.
Here is a fiddle http://jsfiddle.net/yogeshgadge/02y1jjau/1/ where it works - tbody changed to div.
Here is one demo where tbody does NOT work http://jsfiddle.net/yogeshgadge/2tk3u7hq/4/
Nested ng-repeat
Try this - moved the ng-repeat on <tr>
<tbody>
<tr ng-repeat="history in orderHistory">
<td>{{history.reference_code}}</td>
<div ng-repeat="items in history.orderedItems">
<td>{{items.product_description}}</td>
<td>{{items.quantity}}</td>
</div>
<td>
</tr>
</tbody>
This could work properly.
<table>
<thead>
<tr>
<th></th>
<th>Claim Id</th>
<th>Job Number</th>
<th>Project</th>
<th>Created On</th>
<th>Error</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="jobData in createJobResponseData.data">
<td class="counterCell"></td>
<td>{{jobData.claimId}}</td>
<td>{{jobData.jobNumber}}</td>
<td>{{jobData.project}}</td>
<td>{{jobData.createdOn}}</td>
<td >
<div class="counterCellDiv" ng-repeat="error in jobData.errorList">
{{error.errorMessage}}
</div>
</td>
</tr>
</tbody>
$scope.createJobResponseData = {
'status': '200',
'message': 'Request processed successfully',
'data': [
{
'claimId': 'data1',
'claimLineId': '1',
'errorList': null,
'insertedIntoDb': true,
'jobNumber': 'nn001',
'project': 'pro0',
'repairStatus': '5'
},
{
'claimId': 'ASD',
'claimLineId': '1',
'errorList': [{
'errorCode': ')01',
'errorMessage': 'accidentDescription cannot be blank'
}, {
'errorCode': '(01)',
'errorMessage': 'abcd cannot be blank'
}],
'insertedIntoDb': true,
'jobNumber': '',
'project': 'asd',
'repairStatus': '5'
},
{
'claimId': 'oiqweo',
'claimLineId': '1',
'errorList': null,
'insertedIntoDb': true,
'jobNumber': 'qoweiu',
'project': 'asq',
'repairStatus': '5'
},
{
'claimId': 'SDDDASD',
'claimLineId': '1',
'errorList': null,
'insertedIntoDb': true,
'jobNumber': 'asdqio',
'project': 'kalsdjjk',
'repairStatus': '5'
}
]
}

Categories

Resources