Knockout.js: Updating objects loaded with mapping plugin - javascript

I want to render a table containing a list of objects my server is sending me. I'm currently doing this:
<table>
<thead>
<tr>
<th>id</th>
<th>Name</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="foreach: services">
<tr>
<td data-bind="text: id"></td>
<td data-bind="text: name"></td>
<td data-bind="text: status"></td>
</tr>
</tbody>
</table>
And the Knockout.js binding part:
var mappedData = komapping.fromJSON('{{{ services }}}');
ko.applyBindings({services: mappedData});
services is a variable containing JSON data and the whole page is rendered with handlebars. So far so good. I'm able to render the data received in the table.
Now the problem: I'd like to receive a notification which tells me that the status of a service has changed, and update the corresponding object within mappedData. The problem is that mappedData seems pretty opaque and I'm unable to retrieve an object and update it given its id.
Help appreciated!

Your mappedData variable at this point will be a knockout array with a bunch of objects that contain knockout observables.
So all you have to do is change the status observable in the correct object from the array.
function updateServiceStatus(id, status) {
var service = mappedData().filter(function(e) { return e.id() == id; });
if (service.length) {
service[0].status(status);
}
}

To get the object, you can write a helper function that will retrieve for you a service object. You could do something like this (assuming mappedData is an observableArray and id observable) :
function get_service_by_id(service_id){
for(var i=0;i<mappedData().length;i++){
if (mappedData()[i].id() === service_id){
return mappedData()[i];
}
}
return false;
}

Related

Angularjs : ngRepeat list down all the data from server

I successfully fetch data by using $http get from php server. But I have no idea how to display the data in Table form by using ngRepear because all the data is in few different project. I am going to display all the object of data into different row of a table. The following shows data I got from php server.
Following glimpse of code can give you idea
$scope.retrievedData = [];
//retrieve data from your server
//take the data into above scope variable
<table>
<tr ng-repeat = "data in retrievedData">
<td>data.AssetDescription</td>
<td>data.AssetNumber</td>
<td>data.ComputerName</td>
</tr>
</table>
You need to add that data to controller variable:
Controller
function YourController($scope, $http) {
$scope.tableData = [];
$http.get('url').then(function(result) {
$scope.tableData = result.data;
});
}
Template
<table>
<thead>
<tr>
<th>Description</th>
<th>Computer name</th>
<th>Borrow date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in tableData ">
<td>{{row.data.AssetDescription}}</td>
<td>{{row.data.ComputerName}}</td>
<td>{{row.data.borrowDate}}</td>
</tr>
</tbody>
</table>

Knockout TypeScript table not rendering data

I have a table, which shows invoices, then a nested table that shows the individual checks made for those invoices. I'm using knockout and typescript to render these tables. I am able to get the invoices to show, however the checks table doesn't show the data. Here's the code so far:
<tbody class="nohighlight" data-bind="foreach: parent.bankDrafts">
<tr>
<td><span data-bind="text: CheckID"></span></td>
<td><span data-bind="text: CheckRunID"></span></td>
<td><span data-bind="text: VendorName"></span></td>
<td><span data-bind="text: CheckDate"></span></td>
<td><span data-bind="text: FormatCurrency(CheckAmount)"></span></td>
<td><span data-bind="text: Globalize.formatCheckRunApproveStatus(ApprovalStatusID)"></span></td>
</tr>
</tbody>
Here's the typescript:
namespace CheckRunApproval {
declare let searchParameter: string;
class SearchCheckRunModel {
public searchParameter = ko.observable<string>(searchParameter || null);
public checkRuns = ko.observableArray<CheckRunModel>(null);
public bankDrafts = ko.observableArray<BankDraftInfoModel>();
}
var model = new SearchCheckRunModel();
export function GetBankDrafts(data: CheckRunModel): void {
CheckRunServiceMethods.GetBankDrafts(data.CheckRunID())
.done(bankDrafts => ko.mapping.fromJS(bankDrafts, null, model.bankDrafts));
}
}
And here's the service call:
public static GetBankDrafts(checkrunID: number): JQueryPromise<BankDraftInfo[]> {
return CommonMethods.doAjax<BankDraftInfo[]>(
"/Corp/Checks/CheckRunApprovalWS.asmx/getBankDrafts",
JSON.stringify({ checkrunID }),
"GetBankDrafts"
);
}
Now the server call does reach the server side code, passing in the correct parameters and returning the list of checks I'm trying to show as part of the invoice. However, the table itself does not have any data.
My thinking is that it has something to do with the way I'm mapping the model to the view model. It could also be the way I've setup the table itself, with the correct knockout attributes, etc. Any help would be greatly appreciated.
Edit: changing parent.bankDrafts to $parent.bankDrafts() it fixed the issue.
You have a typo in your code. Use $parent.bankDrafts instead of parent.bankDrafts in a foreach binding.

Jsreport shows different result when rendering from client and server

I have a template named A and a test Json stored in server.
Using normal setup for jsreport to render PDF work wonder in the server.
Now I want to use Jsreport_client.js to render. I do an AJAX call getJSON to other server and use jsclient to render. But now the data is not sent/processed correctly. The key located near the root of JSON object is correct but the rest is not. Note that the very same JSON render on server correctly
EDIT:
Below is the call
$.getJSON(AJAXurl).success(function (people) {
jsreport.serverUrl = 'http://localhost:5488';
var request = {
template: {
shortid:"rJPUhdmv"
},
data: people
};
jsreport.render('_blank', request);
})
Below is the returned request structure
{
"responseHeader":{
"status":0,
"params":{
"fq":"{!frange l=0.80 }query($q)",
"q":"{!percentage}etco~",
"group.field":"ent_id"
}},
"grouped":{
"ent_id":{
"ngroups":3,
"groups":[{
"groupValue":"214493",
"doclist":{"numFound":1,"docs":[
{
"add_city":"London",
"add_street":"Devonshire Street",
"nam_comp_name":"ETCO INTERNATIONAL COMMODITIES LTD.",
"add_country":"GB",
"add_id":"668638",
"score":1.0}]
}},OTHER GROUP.....]}}},
"highlighting":{
"C":{
"nam_comp_name":["<span class=\"highlight\">ETO</span>"]}
}}
And below is the handler in server
// Can not read any parameters
</thead>
{{#each grouped.ent_id.groups}}
</tr>
<td>{{offsetIndex #index}}</td>
{{#each doclist.docs}}
<td>{{this.nam_comp_name}}</td>
<td>{{convertScore this.score}}</td>
<td>{{this.add_country}} {{this.add_city}} {{this.add_street}}</td>
<td>{{lis_name}}</td>
{{/each}}
</tr>
{{/each}}
Another handler which has both correct and incorrect/unreadable data
{{#responseHeader.params}}
<tr>
<th>Search term</th>
<td>{{sanitizeQuery this.q}}</td> // Read correctly
</tr>
<tr>
<th>Sanction List: </th>
<td>{{sanitizeQuery this.fq.[0]}}</td> // Incorrectly
</tr>
<tr>
<th>Countries:</th>
<td>{{sanitizeQuery this.fq.[1]}}</td> // Incorrectly
</tr>
{{/responseHeader.params}}
<tr>
<th>Search by:</th>
<td>"Method of searching"</td> // Incorrectly
</tr>
<tr>
<th>Found total:</th>
<td>{{grouped.ent_id.ngroups}}</td> // Read correctly
Helpers
function offsetIndex(index) {
return index+1;
}
function convertScore(score) {
a = parseFloat(score);
return a*100;
}
function sanitizeQuery(query) {
a =query
.replace(/{+.*?}+/g, "")
.replace(/\[\[|\]\]/g, "")
.replace(/<.*?>/g, "")
.replace(/add_country:/,"")
.replace(/program_number:/,"")
.replace(/~/,"");
return a;
}
This was a bug with array serialization in jsreport browser client. Now it is fixed.
Please update to jsreport-browser-client-dist#1.0.2 or update whole jsreport where you can also find it in jsreport#1.0.9

orderBy not working with pagination and filters

<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in foods | filter:foodFilter | itemsPerPage:pageSize | orderBy:'created_at_date'">
<td class="col-md-"> {{food.created_at_date}} </td>
</tbody>
</table>
<dir-pagination-controls
max-size= 7
boundary-links="true">
</dir-pagination-controls>
This is only a snippet of my code but its too large to put up. Everything is working except only some of the created_at_date is in order. When I click on a different filter to add in or remove data depending on that filter, only some of it is entered into the correct place. My main question is: is there someway to sort all of the dates properly while still allowing the everything else function as well? All help is welcome, Thanks
(function () {
"use strict";
App.controller('foodsController', ['$scope'],
function($scope) {
$scope.sortDirection = true;
In your controller you can add the method to order the array before you loop over them.
Assuming your foods array has an array of objects, each with a key of created_at_date and a value:
App.controller('foodsController', function($scope) {
$scope.foods = [{
created_at_date: 6791234
}, {
created_at_date: 9837245
}, {
created_at_date: 1234755
}];
// create a method exposed to the scope for your template.
$scope.orderBy = function(key, array) {
// now you've received the array, you can sort it on the key in question.
var sorted = array.sort(function(a, b) {
return a[key] - b[key];
});
return sorted;
}
});
Now on your template, you have a method available to sort your values for you:
<table>
<thead>
<tr>
<th class="col-md-3" ng-click="sortDirection = !sortDirection">Created At</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="food in orderBy('created_at_date', foods) | filter:foodFilter | itemsPerPage:pageSize">
<td class="col-md-"> {{food.created_at_date}} </td>
</tr>
</tbody>
</table>
The orderBy method which we've created on your controller returns an array, but it's just sorted by the key that's sent in as the first argument of the function. The second argument is the original array you're trying to sort.
At least this way you can check if you remove all your other filters to see if it's ordered correctly, if then after you add them back in it changes it's because those filters are also changing the order.

knockout observable array is not updating view on removing elements from array

Here is my view model code
var TopicsViewModel = function() {
var self = this;
var fakeTopicData =
[
];
self.createProfile = function () {
alert("came to create profile");
};
self.editProfile = function () {
alert("came to edit profile");
};
self.removeProfile = function (profile) {
alert("came to remove profile");
fakeTopicData.pop();
self.topicsArr(fakeTopicData);
};
var refresh = function() {
self.topicsArr = fakeTopicData;
};
self.topicsArr = ko.observableArray([]);
refresh();
};
ko.applyBindings(new TopicsViewModel());
Here is my html for the view:
<hr />
<hr />
<table class="table table-striped table-bordered table-condensed">
<tr >
<th>Area</th>
<th>Name</th>
<th>Link</th>
<th>Description</th>
<th>Why</th>
</tr>
<tbody data-bind="foreach : topicsArr">
<tr>
<td data-bind="text :area"> </td>
<td class=""><a data-bind="text:name, click:$parent.editProfile"></a></td>
<td data-bind="text:link"> </td>
<td data-bind="text:desc"> </td>
<td data-bind="text:why" ></td>
<td><button class="btn btn-mini btn-danger" data-bind="click:$parent.removeProfile">remove</button></td>
</tr>
</tbody>
</table>
<script src="~/Scripts/Topic.js"></script>
The view initially display all the Topics in my fakeData Array.
On clicking the remove Button, I am trying to remove an element from the array, and expected the view to refresh and not show the removed item any more. However the view still shows all the 3 topics.
Could someone please point to what I might be doing wrong.
I spend a long time researching the other similar queries on stackoverflow, but am still stuck. Thanks so much for any insight into this issue.
You are replacing your observable array called topicsarr with one which isn't observable in your refresh method...
Change
var refresh = function() {
self.topicsArr = fakeTopicData;
};
to
var refresh = function() {
self.topicsArr(fakeTopicData);
};
you have 2 issues in your code.
First, you are setting your observableArray topicsArr with non observableArray or normal array in refresh function. Instead use self.topicsArr(fakeTopicData)
Second, in function removeProfile you are using pop() to remove profile element. From KnockoutJS documentation:
myObservableArray.pop() removes the last value from the array and
returns it
So, it's better to use remove(item) and pass to it your profile element or loop through your array and remove that specific item
myObservableArray.remove(someItem) removes all values that equal
someItem and returns them as an array

Categories

Resources