I have a table with some data to view in html. when i do click print, i need to get all the data from db and print it. I am getting the data and populating the model data when i click on print, only the model is updated and print shows the old data. In the code below, newitems is not added to items when i click on print.
http://jsfiddle.net/vijaivp/Y3BJa/306/
HTML
<div ng-app>
<div class="hidden-print" ng-controller="PrintCtrl">
<br />
<div id="overallPrint" class='visible-print' style="float:left; margin-right:50px;">
<h4>Overall Report</h4>
<table border="1">
<thead>
<tr>
<td>Name</td>
<td>Price</td>
<td>Quantity</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>{{item.Name}}</td>
<td>{{item.Price}}</td>
<td>{{item.Quantity}}</td>
</tr>
</tbody>
</table>
<br>
<input type="button" value="Print Overall" ng-click='printOverallReport()' />
</div>
</div>
</div>
JS
function PrintCtrl($scope, $window, $q) {
$scope.items = [
{Name: "Soap", Price: "25", Quantity: "10"},
{Name: "Shaving cream", Price: "50", Quantity: "15"}
];
$scope.newitems = [
{Name: "Shampoo", Price: "100", Quantity: "5"}
];
$scope.printOverallReport = function () {
$scope.items.push($scope.newitems[0]);
$window.print();
};
}
Using a timeout with Angular's $timeout service will fix it:
function PrintCtrl($scope, $window, $q, $timeout) {
$scope.items = [
{Name: "Soap", Price: "25", Quantity: "10"},
{Name: "Shaving cream", Price: "50", Quantity: "15"}
];
$scope.newitems = [
{Name: "Shampoo", Price: "100", Quantity: "5"}
];
$scope.printOverallReport = function () {
$scope.items = $scope.newitems;
console.log($scope.items.length);
$timeout($window.print, 0);
console.log($scope.items.length);
};
}
Fiddle
For a comprehensive explanation as to why, please see DVK's answer (2nd one) here: Why is setTimeout(fn, 0) sometimes useful?
TL:DR;
When you call $window.print() the old HTML is still present since the browser hasn't rendered it yet. It's waiting to finish the javascript function run. setting a $timeout 0 will queue the print at the end of execution queue and will guarantee it happens after the HTML has been rendered. (I still strongly recommend to read his answer)
Related
I'm having trouble with displaying my json data correctly. I want to get each products and place them into it's own row.
The problem now is that it places all the data of for example the value "name" into one table row instead of multiple rows.
This is my json data
{
id: "FVFkkD7s8xNdDgh3zAyd",
name: "AlperKaffe",
products: [
{
id: "0cfBnXTijpJRu14DVfbI",
name: "Første Kaffe",
price: "1",
size: "small",
quantity: "20 ml"
},
{
id: "JQadhkpn0AJd0NRnnWUF",
name: "Anden Kaffe",
price: "2",
size: "Medium",
quantity: "25 ml"
},
{
id: "UwHHdH8bFxbVHkDryeGC",
name: "kaffeeen",
price: "300",
size: "Small",
quantity: "23 ml"
},
{
id: "WiX5h0wFMNkCux9cINYq",
name: "kaffe modal",
price: "230",
size: "Medium",
quantity: "39 ml"
},
this is my Js file which gets the json data. As you can see i'm only working with the "name" value for now
// Jquery getting our json order data from API
$.get("http://localhost:8888/products", (data) => {
let rows = data.map(item => {
let $clone = $('#frontpage_new_ordertable tfoot tr').clone();
let productsName = item.products.map(prod => `${prod.name}`);
$clone.find('.name').html(productsName);
return $clone;
});
// appends to our frontpage html
$("#frontpage_new_ordertable tbody").append(rows);
});
this is my html file
<body>
<table id="frontpage_new_ordertable">
<tbody>
<tr>
<th>Name</th>
<th>Price</th>
<th>Size</th>
<th>Quantity</th>
<th></th>
</tr>
</tbody>
<tfoot>
<tr>
<td class="name"></td>
<td class="price"></td>
<td class="size"></td>
<td class="quantity"></td>
<td class="buttons"></td>
</tr>
</tfoot>
</table>
<script src="./itemPage.js"></script>
</body>
you must replace
let rows = data.map(item => {
to
let rows = data.products.map(item => {
and
let productsName = item.products.map(prod => `${prod.name}`);
to
let productsName = item.name;
https://jsfiddle.net/ab7t1vmf/3/
The issue in your JS snippet seems to be let rows = data.map(item => { ...
From what you describe, the JSON data is comprised of 3 keys:
id
name
products
You cannot execute a map function directly on a Javascript Object, this function requires an array.
Looking a bit more at your code, I understand you need to display each product on its own row. Thus, you would need to use the map function on data.products which contains an array (of products).
let rows = data.products.map(item => {
// ...
$clone.find('.name').html(item.name);
// ...
// ...
});
Reference: https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/map
How do I stop default sorting inside the ng-repeat for dynamic table data ?
Currently I am getting below order:
Addr | CustomerId | Name
but what I want is below ordering:
CustomerId | Name | Addr
Any Help would me much appreciated.
JS:
app.controller('MyController', function ($scope) {
$scope.Customers = [
{ CustomerId: 1, Name: "John Hammond", Addr:'India'
},
{
CustomerId: 2, Name: "Mudassar Khan", Addr:'India'
},
{
CustomerId: 3, Name: "Suzanne Mathews", Addr:'India'
},
{
CustomerId: 4, Name: "Robert Schidner", Addr: 'India'
}
];
});
HTML:
<table>
<tr >
<th ng-repeat="(key,value) in Customers[0]">{{key}}</th>
</tr>
<tbody ng-repeat="c in Customers">
<tr>
</tr>
</tbody>
</table>
Try this below way. I hope this below snippet result is showing what you want.
angular.module("aaa",[]).controller('MyController', function ($scope) {
$scope.Customers = [
{ CustomerId: 1, Name: "John Hammond", Addr:'India'
},
{
CustomerId: 2, Name: "Mudassar Khan", Addr:'India'
},
{
CustomerId: 3, Name: "Suzanne Mathews", Addr:'India'
},
{
CustomerId: 4, Name: "Robert Schidner", Addr: 'India'
}
];
$scope.keys = Object.keys($scope.Customers[0]);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="aaa" ng-controller="MyController">
<table>
<tr>
<th ng-repeat="key in keys">
{{key}}
</th>
</tr>
<tbody ng-repeat="c in Customers">
<tr>
<td ng-repeat="key in keys">{{c[key]}}</td>
</tr>
</tbody>
</table>
</div>
So objects in JS are inherently unordered. What you can do is just hard code the keys in the header if that will be fixed for that particular table and then print the values in the respective order.
Something like this:
<table>
<tr >
<th>CustomerId</th>
<th>Name</th>
<th>Addr</th>
</tr>
<tbody>
<tr ng-repeat="c in Customers">
<td>{{CustomerId}}</td>
<td>{{Name}}</td>
<td>{{c.Addr}}</td>
</tr>
</tbody>
</table>
Note: I put the ng-repeat on the tr which is probably what you need. I dont think you should put it on the tbody.
Do you mean the sort order of the data or the display order of the columns?
The accepted answer displays the data by the order of the columns as specified, but if you want the data itself sorted then just add a filter to the data like this:
<tbody ng-repeat="c in Customers|orderBy:['CustomerId','Name','Addr']">
This sorts the actual data in the list by the fields specified.
My json looks like this :
[{"Name":["A","B","C","D","E","F"], "Age":["20","30","40","50","55","60"], "Gender":["M","M","F","M","Unknown","Unknown"]}]
I want a table in angularjs similar to this
Name Age Gender
A 20 M
B 30 M
C 40 F
I could see many example when my json is similar to this :
[
{Name: "A", Age: "20", Gender: "M"},
{Name: "Bag", Age: "30", Gender: "F"},
{Name: "Pen", Age: "40", Gender: "F"}
];
But I don't know how to proceed with my json. Could anyone help with this?
Assuming your property arrays all have the same number of elements (and are properly arranged) you could use the $index of ng-repeat.
<table>
<thead>
<tr>
<td>Name</td>
<td>Age</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="name in obj.Name">
<td>{{name}}</td>
<td>{{obj.Age[$index]}}</td>
<td>{{obj.Gender[$index]}}</td>
</tr>
</tbody>
</table>
Alternatively (using the same assumption that the data is well-formed), you can just use javascript to consolidate the three separate lists into a single list of person objects. Then you can proceed like the other examples you've seen.
Javascript might look something like this:
$scope.people = [];
obj.Name.forEach(function(name, index) {
people.push(
{
Name: name,
Gender: obj.Gender[index],
Age: obj.Age[index]
});
});
Then a simple ng-repeat on the new people array will work.
...
<tbody>
<tr ng-repeat="person in people">
<td>{{person.Name}}</td>
<td>{{person.Age}}</td>
<td>{{person.Gender}}</td>
</tr>
</tbody>
Try something.
<div ng-repeat="user in users.Name">
Name : {{user}} Age : users.Age[$index] Gender : users.Gender[$index]
</div>
I assume your object is sequenced and arranged
Use lodash _.zip function to arrange them in array, and _.map to convert it to json objects using custom function:
var rows = _.zip(users.Name, users.Age, users.Gender); // [["A",20,"M"],...]
$scope.users =
_.map(rows, function(row) {
return {Name: row[0], Age: row[1], Gender: row[2]}
});
and then iterate them getting values:
<table ng-controller="UsersTableController">
<thead>
<th>NAME</th>
<th>AGE</th>
<th>GENDER</th>
</thead>
<tbody>
<tr ng-repeat="user in users">
<td>{{user.Name}}</td>
<td>{{user.Age}}</td>
<td>{{user.Gender}}</td>
</tr>
</tbody>
</table>
reference: https://lodash.com/docs#zip , https://lodash.com/docs#map
I am trying to set the model of a DOM element to a specific child object given a specific attribute. in this specific example, the "Employees" object is structured in this fashion:
var Employees = [
{EmployeeID:1000
Name: Jimmy
ManagerID: null}
{EmployeeID:1001
Name: James
ManagerID: 1000}
{EmployeeID:1002
Name: Steve
ManagerID: 1000}
]
I was hoping that an inline Curley Brace Directive using a filter would be able to help me out with it. What follows obviously doesn't work, but hopefully it demonstrates what I would like it to do.
<div ng-repeat="Emp in Employees">
<span>Employee #:{{Emp.EmployeeID}}</span>
<img src="../../Content/images/Photos/{{Emp.EmployeeID}}.jpg"/>
<h4>{{Emp.Name}}</h4>
<h5>Manager:</h5>
<!--The following is what I do not know how to do-->
<span>{{Employees.Name | filter:Employees.EmployeeID = Emp.EmployeeID }}</span>
</div>
With the End Result being:
Employee #:1000
<img>
Jimmy
Manager:
<!--I'll figure out what to do with null values in a bit. first things first-->
Employee #:1001
<img>
James
Manager:
Jimmy
Employee #:1002
<img>
Steve
Manager:
Jimmy
The JS
angular.module("myApp", []).controller("MyCtrl", function($scope){
$scope.employees = [
{EmployeeID:1000,
Name: 'Jimmy',
ManagerID: null},
{EmployeeID:1001,
Name: 'James',
ManagerID: 1000},
{EmployeeID:1002,
Name: 'Steve',
ManagerID: 1000}
]
$scope.findManager = function(empId) {
console.log('here');
//debugger;
for(var i=0; i<$scope.employees.length; i++)
{
var curEmployee = $scope.employees[i];
console.log(curEmployee.EmployeeID)
if(curEmployee.EmployeeID == empId)
return curEmployee.Name;
}
return "";
}
});
The HTML
<div ng-app="myApp" ng-controller="MyCtrl">
<div ng-repeat="Emp in employees">
<span>Employee #:{{Emp.EmployeeID}}</span>
<img ng-src="../../Content/images/Photos/{{Emp.EmployeeID}}.jpg"/>
<h4>{{Emp.Name}}</h4>
<h5>Manager:</h5>
<!--The following is what I do not know how to do-->
<span>{{findManager(Emp.ManagerID)}}</span>
</div>
</div>
The fiddle
http://jsfiddle.net/EhJLu/
I need to show a details view based on a selected row in a table. I would like to show which row is currently selected in the table. Is it possible to do this with the 'style' binding?
I've created a JSFidle with some code illustrating the idea...or lack of, since it currently all rows change color on row click. Here's the code:
<table>
<tr>
<th>Name</th>
<th>Sales</th>
<th>Price</th>
</tr>
<tbody data-bind='template: { name: "fieldTemplate", foreach: viewModel.items}'></tbody>
</table>
<script type="text/html" id="fieldTemplate">
<tr >
<td> ${name}</td>
<td>${sales}</td>
<td>${price}</td>
</tr>
</script>
And this is the Javascript:
var viewModel = {
items: ko.observableArray([
{ name: "Well-Travelled Kitten", sales: 352, price: 75.95 },
{ name: "Speedy Coyote", sales: 89, price: 190.00 },
{ name: "Furious Lizard", sales: 152, price: 25.00 },
{ name: "Indifferent Monkey", sales: 1, price: 99.95 },
{ name: "Brooding Dragon", sales: 0, price: 6350 },
{ name: "Ingenious Tadpole", sales: 39450, price: 0.35 },
{ name: "Optimistic Snail", sales: 420, price: 1.50 }
])
};
So I think I need a reference to the current row, or adding a style attribute to my item and then bind to this, and then change in the click event. Any ideas?
You'll need to bind a click event to each row of the table. Once a row is clicked. then in the event handler you can change the color of the selected row + you can show the new details
something like this > http://jsfiddle.net/wrzFx/11/
I would bind a selection event on a table row via jQuery live events. Inside the listener I would change the value of selectedRow attribute in your viewModel
That might not sound a Knockout way to do things but as long as it works I'm ok with it.
BTW, I can't get jQuery templates running inside jsFiddle for some reason.