I was trying to display records on html using ngTable. The records are retrieved from server side through rest api.
html:
<div class="container">
<table ng-table="tableParams" class="table" show-filter="false">
<tr ng-repeat="report in $data">
<td title="'ReportId'" filter="{ reportid: 'text'}" sortable="'reportid'">
{{report.reportid}}</td>
<td title="'SampleId'" filter="{ sampleid: 'text'}" sortable="'sampleid'">
{{report.sampleid}}</td>
<td title="'MRN'" filter="{ mrn: 'text'}" sortable="'mrn'">
{{report.mrn}}</td>
<td title="'Diagnosis'" filter="{ diagnosis: 'text'}" sortable="'diagnosis'">
{{report.diagnosis}}</td>
</tr>
</table>
</div>
Controller.js
ristoreApp.controller("fmCtrl",
['$scope', 'fmFactory', 'NgTableParams', function($scope, fmFactory, NgTableParams) {
$scope.selection = '0';
$scope.fmSearch = function () {
if ($scope.selection == '0') {
$scope.tableParams = new NgTableParams({
page: 1, // show first page
count: 10 // count per page
}, {
getData: function (params) {
return fmFactory.getAll().then(function(data) {
params.total(data.inlineCount);
return data.results;
});
}
});
$scope.tableParams.reload();
}
}
}]
)
Factory js
ristoreApp.factory("fmFactory", ['$http', '$window',
function ($http, $window) {
var service = {};
service.getAll = function () {
var url = SERVER + "/ristore/foundation/";
return $http({
headers: {'Authorization': 'Bearer ' + $window.localStorage.getItem("access_token")},
url: url,
method: 'GET',
crossOrigin: true
})
}
return service;
}]);
The factory definitely returns records from server correctly, because when I debug it, it shows the data of the response.
However it does not show anything on the page. What went wrong?
Do these things
Change $scope.tableParams in controller to this.tableParams
Change <div ng-controller="fmCtrl"> in view to <div ng-controller="fmCtrl as fm">
Change ng-table="tableParams" in view to ng-table="fm.tableParams"
Documentation: http://ng-table.com/#/loading/demo-external-array
Update 1: Change the return rmFactory.getAll() like this,
return fmFactory.getAll().then(function(response) {
var reports = response.data;
params.total(reports.length);
return reports;
});
Update 2: Add this line to controller beginning (first line)
var self = this;
The first change we made, rewrite it like this.
self.tableParams
Update 3: We removed $scope and used this because the documentation was using that. this did not work here because, we were inside $scope.fmSearch. So to get this of the controller, we stored it in a variable self and accessed it. You can rename self to any name of your choice.
Related
I have this knockout view
var ViewModel = function (data) {
if (data != null) {
ko.mapping.fromJS(data, { UsuarioPersonals: UsuarioPersonalMapping },
self);
}
var self = this;
self.UsuarioPersonals = ko.observableArray();
self.search_UsuarioPersonals = ko.observable('');
var UsuarioPersonalsUri = '/api/UsuarioPersonals/';
function ajaxHelper(uri, method, data) {
self.error(''); // Clear error message
return $.ajax({
type: method,
url: uri,
dataType: 'json',
contentType: 'application/json',
data: data ? JSON.stringify(data) : null
}).fail(function (jqXHR, textStatus, errorThrown) {
self.error(errorThrown);
});
}
function getAllUsuarioPersonals() {
ajaxHelper(UsuarioPersonalsUri, 'GET').done(function (data) {
self.UsuarioPersonals(data);
});
}
self.filteredRecords = ko.computed(function () {
return ko.utils.arrayFilter(self.UsuarioPersonals(), function (rec) {
return (
(self.search_UsuarioPersonals().length == 0 || rec.Email().toLowerCase().indexOf(self.search_UsuarioPersonals().toLowerCase()) > -1)
)
});
});
var UsuarioPersonalsDetail = function (data) {
var self = this;
if (data != null) {
self.Id = ko.observable(data.Id);
self.Email = ko.observable(data.Email);
self.Password = ko.observable(data.Password);
}
}
var UsuarioPersonalMapping = {
create: function (options) {
return new UsuarioPersonalsDetail(options.data);
}
};
// Fetch the initial data.
getAllUsuarioPersonals();
};
ko.applyBindings(new ViewModel());
and html page where i want records be filtered by email field.
<div class="row">
<div class="col-md-3">
email: <input data-bind="value: search_UsuarioPersonals, valueUpdate: 'afterkeydown'" /><br />
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Filtro</h2>
</div>
<table class="table">
<tbody data-bind="foreach: filteredRecords">
<!-- <tr><td> Nombre contiene: <input data-bind=" value:=" valueupdate: ="" /></td></tr>-->
<!--<tbody data-bind="foreach: filteredRecords">-->
<tr>
<td data-bind="text: Id"></td>
<td data-bind="text: Email"></td>
<td data-bind="text: Password"></td>
</tr>
</tbody>
</table>
</div>
</div>
what is wrong that the filtered results show correctly? So data get from server are filtered with Email field. Everytime page is loaded, all datafield are put in is right data-bind but when i write a value in the input field nothing happen.
When your ajax call returns you are setting UsuarioPeronals equal to the raw data. The data has no observable properties they are just text, so your filter function throws an error when it tries to use Email with parenthesis like it's an observable (... || rec.Email().toLowerCase()...).
function getAllUsuarioPersonals() {
ajaxHelper(UsuarioPersonalsUri, 'GET').done(function (data) {
self.UsuarioPersonals(data);
});
}
You'll need to use the same UsuarioPersonalMapping on it that you reference at the top of your viewmodel or loop through the data returned and create a new UsuarioPersonalsDetail for each one.
Looks like when computed is called, the self.UsuarioPersonals() does not have data. Can you use observableArray instead of computed ? or computed is the requirement?
I am using angular routers
app.config(function($routeProvider) {
$routeProvider
.when('/comment/list', {
templateUrl: 'commentList.htm',
controller: 'mainController'
})
});
<td ng-show="btnUADetails" ng-click="loadPage('commentList', x.userName);">
<a class="detailButton" href="#/comment/list"></a>
</td>
and here is my angular function
$scope.loadPage = function(pageId, id) {
if (pageId == "commentList") {
$scope.getServerData($scope.generateUrl(pageId, 'json', id)).then(function(result) {
$scope.serverComment = result;
});
} else {
//do something
}
}
Before $HTTP returns response html page loads and i am getting clean data in html table . Can i load this page after my functions returns result ? Or load html file first and load it again when functions returns result ?
When the router changes routes, it destroys the $scope of the current view and creates a new $scope with a new instance of the controller.
Include any information the new view needs as query parameters in the new URL.
Change the link to include a parameter:
<td ng-show="btnUADetails" ̶n̶g̶-̶c̶l̶i̶c̶k̶=̶"̶l̶o̶a̶d̶P̶a̶g̶e̶(̶'̶c̶o̶m̶m̶e̶n̶t̶L̶i̶s̶t̶'̶,̶ ̶x̶.̶u̶s̶e̶r̶N̶a̶m̶e̶)̶;̶"̶ >
<a class="detailButton" href="#/comment/list?id={{x.userName}}"></a>
</td>
Use the parameter in the controller:
app.controller("mainController", function($scope, $route) {
this.$onInit = function() {
if ($route.current.templateUrl == 'commentList.htm') {
var pageId = 'comment';
var id = $route.current.params.id;
$scope.getServerData($scope.generateUrl(pageId, 'json', id))
.then(function(result) {
$scope.serverComment = result;
});
};
};
});
In the above example, the new instance of the controller uses the current params of the router to load the necessary data.
I am trying a simple binding using JsonResult from MVC Controller. The json comes back but the bindings in knockout observable array does work. Below is my code.
If I put the json result directly to the observable it works. I am not sure what I am missing here.
Knockout Code
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/knockout-min.js"></script>
<script src="~/Scripts/knockout.mapping.js"></script>
var viewModel;
vmListModel = function () {
var self = this;
self.Products = ko.observableArray([]);
self.GetData = function () {
$.ajax({
url: '#Url.Action("product", "employees")',
cache: false,
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: {},
success: function (rs) {
console.log(rs); //--> the data returns like this { Id: '1001', Name: 'xavier' }
//self.Products({ Id: '1001', Name: 'xavier' }); // if I put this it binds
ko.mapping.fromJS(rs, {}, self.Products);
//self.Products(ko.mapping.fromJS(rs));
}
});
}
};
$(document).ready(function () {
viewModel = new vmListModel();
ko.applyBindings(viewModel, $('#products1')[0]);
viewModel.GetData();
});
HTML
<table id="products1">
<thead>
<tr>
<th>
ID
</th>
<th>
Name
</th>
</tr>
</thead>
<tbody data-bind="foreach:Products">
<tr>
<td data-bind="text:Id">
</td>
<td data-bind="text:Name">
</td>
<td>
</td>
</tr>
</tbody>
Controller code
public JsonResult Product()
{
string variablename = "{Id:'1001',Name:'xavier'}";
return Json(variablename, JsonRequestBehavior.AllowGet);
}
Error
Uncaught ReferenceError: Unable to process binding "text: function (){return Id }"
Message: Id is not defined
Your are passing data of type string from controller and trying to convert using mapping plugin which is wrong in all sorts
FIX: Build a array and pass it . so mapping plugin will convert everything to observable's and you can have successful 2-way binding intact .
Controller :
var data = new[] { new { Id = "1001", Name = "Nancy" }, new { Id = "1002", Name = "bunny" } };
return Json(data, JsonRequestBehavior.AllowGet);
Hope that helps
I want to update KnockoutJS viewmodel from AJAX JSON entry. I am unsure how to do this.
Here is my code:
var CurrencyModel = function (Currencies) {
var self = this;
self.Currencies = ko.observableArray(Currencies);
self.AddCurrency = function () {
self.Currencies.push({
CurrencyFrom: "",
CurrencyTo: ""
});
};
self.RemoveCurrency = function (Currency) {
self.Currencies.remove(Currency);
};
self.Save = function (Form) {
alert("Could Now Save: " + ko.utils.stringifyJson(self.Currencies));
};
$.ajax({
url: "CurrencyConfiguration.aspx/GetConfiguredCurrencies",
// Current Page, Method
data: '{}',
// parameter map as JSON
type: "POST",
// data has to be POSTed
contentType: "application/json; charset=utf-8",
// posting JSON content
dataType: "JSON",
// type of data is JSON (must be upper case!)
timeout: 10000,
// AJAX timeout
success: function (Result) {
//Need to Get method to Bind To CurrencyModel;
},
error: function (xhr, status) {
alert(status + " - " + xhr.responseText);
}
});
};
$(document).ready(function () {
var VM = new CurrencyModel();
ko.applyBindings(VM);
})
And here is the JSON Data that is obtained from the server:
{
"d": [
{
"__type": "Finance.Tracntrace.Members_Only.DAL.DataModel.Currency.CurrencyConfigurationDM",
"CurrencyFrom": "ZAR",
"CurrencyTo": "USD"
},
{
"__type": "Finance.Tracntrace.Members_Only.DAL.DataModel.Currency.CurrencyConfigurationDM",
"CurrencyFrom": "USD",
"CurrencyTo": "ZAR"
}
]
}
HTML:
<table class="table table-striped">
<thead>
<tr>
<th>
Currency From
</th>
<th>
Currency To
</th>
</tr>
</thead>
<tbody data-bind="foreach: Currencies">
<tr>
<td data-bind="text: CurrencyFrom">
</td>
<td data-bind="text: CurrencyTo">
</td>
</tr>
</tbody>
</table>
The Viewmodel Is extremely Simple, I have a currency From, and A currency to that I want to add and remove from a table.
I'd do two things here.
First, define a class for Currency.
var currency = function(data) {
var self = this;
self.CurrencyFrom = ko.observable(data.CurrencyFrom);
self.CurrencyTo = ko.observable(data.CurrencyTo);
}
After that, your success method becomes something like this.
success: function(Result) {
// use jQuery's $.map function to translate values
// should be stored in .d property, according to your JSON
var mappedCurrencies =
$.map(Result.d,
// Here, $.map will just new up a new currency,
// using the constructor argument to set fields
function(item){ return new currency(item);});
// Finally, set the currencies. VM should update automatically.
self.Currencies(mappedCurrencies);
}
I suggest you to separate viewmodel and datacontext. It's a better practice to have a class for your ajax request
I supose that you need to bind you array "self.Currencies" with data received from a service, so you only need to do this on your success function:
success: function (Result) {
ko.utils.arrayPushAll(self.Currencies, Result);
}
I have an existing view model that lists currency codes that I want the conversion rates for. I utilize the Yahoo Finance API to get a JSON result for my Currencies.
How do I bind this 3rd Party JSON result to my existing ViewModel.
JSON from Yahoo Finance API:
parseExchangeRate({"query":{"count":1,"created":"2013-01-17T07:37:18Z","lang":"en-US","results":{"row":{"rate":"8.7967","name":"USD to ZAR"}}}});
My Viewmodel Code:
var currency = function (data) {
var self = this;
self.CurrencyFrom = ko.observable(data.CurrencyFrom);
self.CurrencyTo = ko.observable(data.CurrencyTo);
self.ConversionRate = ko.observable(getRate(data.CurrencyFrom, data.CurrencyTo));
}
var CurrencyModel = function (Currencies) {
var self = this;
self.Currencies = ko.observableArray(Currencies);
self.AddCurrency = function () {
self.Currencies.push({
CurrencyFrom: "",
CurrencyTo: "",
ConversionRate: ""
});
};
self.RemoveCurrency = function (Currency) {
self.Currencies.remove(Currency);
};
self.Save = function (Form) {
alert("Could Now Save: " + ko.utils.stringifyJson(self.Currencies));
};
$.ajax({
url: "CurrencyConfiguration.aspx/GetConfiguredCurrencies",
// Current Page, Method
data: '{}',
// parameter map as JSON
type: "POST",
// data has to be POSTed
contentType: "application/json; charset=utf-8",
// posting JSON content
dataType: "JSON",
// type of data is JSON (must be upper case!)
timeout: 10000,
// AJAX timeout
success: function (Result) {
var MappedCurrencies =
$.map(Result.d,
function (item) { return new currency(item); });
self.Currencies(MappedCurrencies);
},
error: function (xhr, status) {
alert(status + " - " + xhr.responseText);
}
});
};
//3rd Party JSON result
function getRate(from, to) {
var script = document.createElement('script');
script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D" + from + to + "%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
document.body.appendChild(script);
}
$(document).ready(function () {
var VM = new CurrencyModel();
ko.applyBindings(VM);
})
My HTML:
<table class="table table-striped">
<thead>
<tr>
<th>
Date Updated
</th>
<th>
Currency From
</th>
<th>
Currency To
</th>
<th>
Conversion Rate
</th>
<th />
</tr>
</thead>
<tbody data-bind="foreach: Currencies">
<tr>
<td>
<label class="label">Date</label>
</td>
<td>
<input data-bind="value: CurrencyFrom, uniqueName: true" />
</td>
<td>
<input data-bind="value: CurrencyTo, uniqueName: true" />
</td>
<td>
<input data-bind="value: ConversionRate, uniqueName: true" />
</td>
<td>
<a href='#' data-bind='click: $root.RemoveCurrency'>Delete</a>
</td>
</tr>
</tbody>
</table>
My JSON Return:
{"d":[{"__type":"Finance.Tracntrace.Members_Only.DAL.DataModel.Currency.CurrencyConfigurationDM","CurrencyFrom":"ZAR","CurrencyTo":"USD","Rate":null},{"__type":"Finance.Tracntrace.Members_Only.DAL.DataModel.Currency.CurrencyConfigurationDM","CurrencyFrom":"USD","CurrencyTo":"ZAR","Rate":null}]}
I've got to admit, I'm not 100% sure what you actually are asking, but I presume that you are after an implementation of the parseExchangeRate you are using as the jsonp callback method?
In your case, you'll need to dive into that Yahoo return object to get the name property (query.results.row.name at a guess) and split that string to get your two currencies.
function parseExchangeRate(yahooData)
{
var currencies = yahooData.query.results.row.name;
// split the string to get your two currencies
var from = whatever;
var to = whatever;
var rate = yahooData.query.results.row.rate;
I'd then change your AddCurrency method to take a data object
CurrencyModel.AddCurrency(from, to, rate);
}
self.AddCurrency = function (from, to, rate) {
self.Currencies.push({
CurrencyFrom: from,
CurrencyTo: to,
ConversionRate: rate
});
};
Is that what you're after?