I have created a jsbin at http://jsbin.com/ifimadOw/11/edit to illustrate.
I have this listview object:
<ul id="marketplace-categories-listview" data-bind="source: results"></ul>
And I have this dataset:
dsCats = new kendo.data.DataSource({
transport: {
read: {
url: myUrl,
data: {
key: myKey
}
}
}
});
$("#marketplace-categories-listview").kendoMobileListView({
dataSource: dsCats,
template: $("#marketplace-product-template").text()
});
The data returned from the API looks something like this:
{"count": 3, "results": ["Acupuncture Therapy","Automobiles","Lawn Care"]}
And here is my template:
<script type="text/x-kendo-tmpl" id="marketplace-categories-template">
<li data-bind="text: this"></li>
</script>
Because my data doesn't have named elements, I can't use something like "#:category#" in the template. I have also tried data-bind (as above), but so far nothing works. Surely there is a way to do this.
Simply use data (which is the name of the context variable passed to the template function) in your template:
$("#category-listview").kendoMobileListView({
dataSource: dsCats,
template: "#= data #"
});
(updated JSBin)
Related
I am using Kendo ListView with remote datasource. I would like to add links to the data that is displayed but I am struggling.
Here is my function:
$(function () {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: URL + "/Read",
dataType: "json"
}
},
schema: {
data: function (response) {
return response.Data["dsStudent"]["ttStudent"];
},
},
});
$("#listView").kendoListView({
dataSource: dataSource,
selectable: "multiple",
dataBound: onDataBound,
change: onChange,
template: kendo.template($("#template").html())
});
function onDataBound() {
//console.log("ListView data bound");
}
function onChange() {
var data = dataSource.view(),
selected = $.map(this.select(), function (item) {
return data[$(item).index()].fileID;
});
console.log("Selected: " + selected.length + " item(s), [" + selected.join(", ") + "]");
}
});
Here is my template
<script type="text/x-kendo-tmpl" id="template">
<div class="product">
<ul class="list-group">
<li class="list-group-item">#:Name#</li>
</ul>
</div>
</script>
The data is displayed as expected. My JSON contains a value that I would like to append to a url, this would then be used to create the href link. This is where I am struggling.
I have been able to console.log the value I need form my JSON but I am lost trying to figure out how to create the href.
Here is a snippet of my JSON:
{"Data": {"dsStudent": {"ttStudent": [{"studentNum": 366,"studentVersion": 2,"createDate": "2018-02-11","fileID":"18525478387e8","description":"StudentNames.pdf","displayCreateTime": "15:31"}]}}}
Using the onChange function, I am able to console.log the required field from the JSON.
I am trying to output the results like this, the fileID would change for each record in the JSON file.
<ul>
<li>
Download Student Record
</li>
</ul>
I hope I have been able to explain where I am struggling.
Just do like in your first template, print the value:
Download Student Record
^ here is where you print the fileId inside the link address
I'm trying to include button details which allows to go to page detail
$("#Grid").ejGrid({
dataSource: ej.DataManager({
...
columns: [
{ headerText: 'Detail', commands: ['type:"detail", buttonOptions:{text: "details", click:"OnClick"}} ],},
],
And then I defined my function:
function OnClick(id){
var url = '#Url.Action("Detail","ServicesOrder", new {id="__id__"})';
window.location.href=url.replace('__id__',id);
}
my controller ServicesOrder
public IActionResult Detail(int id)
{ServicesOrder ServicesOrder = _context.ServicesOrder.SingleOrDefault(x => x.ServicesOrderId.Equals(id));
if (ServicesOrder == null)
{
return NotFound();
}
return View(ServicesOrder);
}
the mistake I get
This site page is not found at:
https: // localhost: 44337 / ServicesOrder/Detail/[object% 20Object]
I have followed to the letter your code, but is not working (see image).
normally I would do this in a template with Syncfusion controls just works better and the tag-helpers just work.
//OPTION 1
//your original source
$("#Grid").ejGrid({
dataSource: ej.DataManager({
columns: [
{ headerText: 'Detail' template: "<a href='/ServicesOrder/Details/{{:OrderId}}'>Finiched</a>"},
{ headerText: 'Order #', field: 'OrderId'}]
});
//OPTION 2
//your original source + tweak
$("#Grid").ejGrid({
dataSource: ej.DataManager({
columns: [
{ headerText: 'Detail', template: true, templateId: "#detailsbutton"}]
});
<script type="text/x-jsrender" id="detailsbutton">
<a class="btn btn-primary" href="#Url.Action("Details", "ServicesOrder", new {id = {{:OrderId}})>Details</a>
</script>
As long as the OrderId exists in the query for the grid it will find that in the template and populate accordingly. Keep in mind Syncfusion uses JSX extensively under the covers (at least this version which is EJs1, EJs2 is a complete rewrite using pure Javascript). I
I really have to emphasize that using just javascript with asp.net core mvc works but adding in clean tag-helpers like:
<ejs-grid id="OrderGrid" dataSource=#ViewBag.somedata >
<e-datamanager></e-datamanager>
<e-grid-columns>
<e-grid-column field="Id" type="number"></e-grid-column>
</e-grid-columns>
</ejs-grid>
So much easier to deal with!
I am trying to set up an example in which a series of news items will be passed in using ajax in a json format. At the moment I am just using a function to simulate returned data.
Here is the jsfiddle: http://jsfiddle.net/c8b4naL5/
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
<span data-bind="foreach: { data: newsItems, as: 'item' }" >
<!-- <span data-bind="foreach: { data: items, as: 'item' }"> -->
<div class="news-item">
<span data-bind='text:item.title'></span>
</div>
</span>
<script type="text/javascript">
function NewsItemsCall(){
return {
newsItemsFromCall: [
{title:'First Title From call'},
{title:'Second Title From call'}
]
}
}
function NewsItem(newsItemsCall){
var map = ko.mapping.fromJS(newsItemsCall);
return map;
}
var viewModel = {
newsItems:ko.observableArray([new NewsItem(new NewsItemsCall())])
}
ko.applyBindings(viewModel);
</script>
The ko.toJSON displays the following:
{
"newsItems": [
{
"newsItemsFromCall": [
{
"title": "First Title From call"
},
{
"title": "Second Title From call"
}
],
"__ko_mapping__": {
"ignore": [],
"include": [
"_destroy"
],
"copy": [],
"observe": [],
"mappedProperties": {
"newsItemsFromCall[0].title": true,
"newsItemsFromCall[1].title": true,
"newsItemsFromCall": true
},
"copiedProperties": {}
}
}
]
}
At this point I am just trying to get it to work to display the data in the template. Any insights would be appreciated. Thanks in advance.
Well the modification required could be approached from either the data side or the client side. At face value, your view isn't matched up to the data due to newsItems containing an array of newItemsFromCall. If the data is in the correct format, then just add another foreach binding.
Modifying the data
NewsItemsCall could return an array instead of an object
be aware of the return of the mapping call depending on how you will be using that value elsewhere
Modifying the UI
<span data-bind="foreach: { data: newsItems, as: 'item' }" >
<div data-bind='foreach: item.newsItemsFromCall'>
<span data-bind='text: title'></span>
</div>
</span>
Modified fiddle with changes to the data structure. I also included an alternate approach that maps the fromJS call directly as a viewmodel.
Example of mocking json calls in a fiddle.
In knockout.js, is it possible to let the right-hand-side of a binding (the value of the binding) be dynamic? For example,
<input data-bind="value: dynamicBinding()"/>
<script type="text/javascript">
var vm = {
dynamicBinding : function() {
return "foo().bar";
},
foo : ko.observable({
bar : ko.observable("hi");
}
};
ko.applyBindings(vm);
</script>
the result should be that the the dynamicBinding function is executed while applying the bindings and the resulting string is used as the binding. The input element should be bound to foo().bar, which is the observable with the value "hi".
If you wonder why I would want this, I am trying to render a dynamic table with knockout, where both the rows and the columns are observableArrays, and I want to allow the column definitions to contain the expression of the binding for that column. I.e., I want to be able to do this:
<table data-bind="foreach: data">
<tr data-bind="foreach: $root.columns">
<td data-bind="text: cellValueBinding()"></td>
</tr>
</table>
<script type="text/javascript">
var vm = {
data: ko.mapping.fromJS([
{title: "Brave New World", author: { name : "Aldous Huxley" },
{title: "1984", author: { name : "George Orwell" },
{title: "Pale Fire", author: { name : "Vladimir Nabokov" }]),
columns: ko.observableArray([
{header: "Title", cellValueBinding: function () { return "$parent.title"; }},
{header: "Author", cellValueBinding: function () { return "$parent.author().name"; }}
])
};
ko.applyBindings(vm);
</script>
As you can see from the example, the column definition knows how to extract the value from the data. The table markup itself is more or less a placeholder. But as far as I can tell, this does not work, due to the way knockout processes the bindings. Are there any other options available?
Thanks.
Solution: I ended up using Ilya's suggestion - I can let cellValueBinding be a function that accepts the row and column as arguments, and returns an observable. This technique is demonstrated in this fiddle.
Use ko.computed for it.
Look on example
JSFiddle
EDIT
In your second example, you can pass $parent value ti the function
<td data-bind="text: cellValueBinding($parent)"></td>
and in model
{header: "Title", cellValueBinding: function (parent) { return parent.title; }},
{header: "Author", cellValueBinding: function (parent) { return parent.author().name; }}
JSFiddle
I have a simple Handlebars helper which simply formats a money value. The helper works property when I test with static data, but not when I load data asynchronously. In other words, {{totalBillable}} will output the expected amount, but {{money totalBillable}} will output zero. But only when the data is loaded via an ajax call. What the heck am I doing wrong?
I've tried to pare the code down as much as possible, and also created a jsfiddle here:
http://jsfiddle.net/Gjunkie/wsZXN/2/
This is an Ember application:
App = Ember.Application.create({});
Here's the handlebars helper:
Handlebars.registerHelper("money", function(path) {
var value = Ember.getPath(this, path);
return parseFloat(value).toFixed(2);
});
Model:
App.ContractModel = Ember.Object.extend({});
App Controller:
App.appController = Ember.Object.create({
proprietor: null,
});
Contracts Controller (manages an array of contracts):
App.contractsController = Ember.ArrayController.create({
content: [],
totalBillable: function() {
var arr = this.get("content");
return arr.reduce(function(v, el){
return v + el.get("hourlyRate");
}, 0);
}.property("content"),
When the proprietor changes, get new contract data with an ajax request. When getting data asynchronously, the handlebars helper does not work.
proprietorChanged: function() {
var prop = App.appController.get("proprietor");
if (prop) {
$.ajax({
type: "POST",
url: '/echo/json/',
data: {
json: "[{\"hourlyRate\":45.0000}]",
delay: 1
},
success: function(data) {
data = data.map(function(item) {
return App.ContractModel.create(item);
});
App.contractsController.set("content", data);
}
});
}
else {
this.set("content", []);
}
}.observes("App.appController.proprietor")
});
If I use this version instead, then the Handlebars helper works as expected:
proprietorChanged: function() {
var prop = App.appController.get("proprietor");
if (prop) {
var data = [{
"hourlyRate": 45.0000}];
data = data.map(function(item) {
return App.ContractModel.create(item);
});
App.contractsController.set("content", data);
}
else {
this.set("content", []);
}
}.observes("App.appController.proprietor")
View:
App.OverviewTabView = Ember.TabPaneView.extend({
totalBillableBinding: "App.contractsController.totalBillable"
});
Kick things off by setting a proprietor
App.appController.set("proprietor", {
ID: 1,
name: "Acme"
});
Template:
<script type="text/x-handlebars">
{{#view App.OverviewView viewName="overview"}}
<div class="summary">
Total Billable: {{totalBillable}}<br/>
Total Billable: {{money totalBillable}}<br/>
</div>
{{/view}}
</script>
when using a helper, handlebars does not emit metamorph tags around your helper call. this way, this part of the template is not re-rendered because there is no binding
to manually bind part of a template to be re-rendered, you can use the bind helper:
<script type="text/x-handlebars">
{{#view App.OverviewView viewName="overview"}}
<div class="summary">
Total Billable: {{totalBillable}}<br/>
Total Billable: {{#bind totalBillable}}{{money this}}{{/bind}}<br/>
</div>
{{/view}}
</script>