using knock-out for width of kendo-ui input wrraper - javascript

I work in durandal project (where javascript and html written in separated pages).
I have kendo-combo, and I give it width by declare the wrraper-input width.
It works well. But when I change it to be binded- it does not work.
here is my code (which is not working):
html:
<input id="kendoCombo" data-bind=" value:'444', style:{width:width},
kendoDropDownList: { dataSource: data,
dataValueField:itemValue,
dataTextField: itemText,
value:selectedId,
template: template,
change:onChange}" />
javascript:
width:ko.observable('100px')
When my width has not been binded yet, it works well. Here is my previous html code:
<input style="width:100
id=" kendoCombo "
data-bind=" value: '444',
kendoDropDownList: { dataSource: data,
dataValueField:itemValue,
dataTextField: itemText,
value:selectedId,
template: template,
change:onChange} " />

The problem is that Kendo only set the width of the DropDownList once when it is initialized, so when Knockout updates the width in the style binding it has no effect on the DropDownList.
However you can set width on the wrapper property (requires: Q1 2013 (version 2013.1.319) or newer) of the kendoDropDownList and you can put this logic into a custom bindingHandler:
ko.bindingHandlers.kendoDropDownListWidth = {
update: function (element, valueAccessor) {
var dropdownlist = $(element).data("kendoDropDownList");
dropdownlist.wrapper[0].style["width"] =
ko.utils.unwrapObservable(valueAccessor());
}
};
And use it like this:
<input id="kendoCombo" data-bind=" value:'444',
kendoDropDownListWidth: width,
kendoDropDownList: { dataSource: data,
dataValueField:itemValue,
dataTextField: itemText,
value:selectedId,
template: template,
change:onChange}" />
Demo JSFiddle.

Related

How to refresh ui-grid cell which has a cellFilter to display multiple fields of the bound entity in one cell

I use a cell filter to show multiple properties of a bound entity in one cell. Therefore there is no one field name because it is a computed field. How can I force the grid to reevaluate the cell filter if one of the involved properties changes?
The column definition:
columnDefs: [
{ field: 'xxx', displayName: 'Something', cellFilter: 'concatSomeProps:this' }
]
The filter:
myApp.filter('concatSomeProps', function () {
return function (cellValue, scope) {
var entity = scope.row.entity;
return entity.prop1 + ", " + entity.prop2;
};
});
If have tried to use notifyDataChanged or the refresh function of the grid api but it doesn't work.
I'd probably use a cellTemplate, and not a filter in this case:
{ field: 'xxx', displayName: 'Something', cellTemplate:'template.html' }
And
<script type="text/ng-template" id="template.html">
<div>
{{row.entity.name + row.entity.age}}
</div>
</script>
See this Plnkr I made for you to see what I'm talking about. Edit either one of the first two fields and you will see the concat field change. You'd also change your template to use row.entity.prop1 + row.entity.prop2 to make it work, as my template is for my columns.

knockoutjs kogrid display date within cell - with plunk

I have the following columnDefs
self.columnDefs = [
{ width: 150, field: 'timeReceived', displayName: 'Time Received', cellFilter: function (data) { return moment(data).format('DD/MM/YYYY h:mm a') } },
{ width: 500, field: 'name', displayName: 'Name' },
{ width: 150, field: 'LinkToTimeSent', displayName: 'Time SentX', cellTemplate: '<a data-bind="text:$parent.entity.timeSent, attr: { href: $parent.entity.linkToTimeSent}" ></a>' },
];
My problem is with the Time SentX. I'd like this to display the content of entity.timeSent but converted for human consumption using the moment library.
How can I call the function moment($parent.entity.timeSent).format('DD/MM/YYYY h:mm a') from within my columnDefs?
In the following plunk, line 96 needs to contain something like
text:moment($parent.entity.TimeSent, "DD/MM/YYYY h:mm a") but I can't get it to work!
:https://plnkr.co/edit/jNn3knbnCCbBQu9NgKze?p=preview
Edit: My answer was a bit too general. An attempt to be more specific.
Map your WorkflowRules to their own "viewmodels", and you can do anything you like:
this.workflowRules = ko.observableArray(sampleData.WorkflowRules
.map(function(jsonRule) {
// Add UI helpers (create a sort of viewmodel)
var timeSentMoment = moment(jsonRule.TimeSent);
// Purely for display purposes:
jsonRule.timeSentLabel = timeSentMoment.format('DD/MM/YYYY h:mm a');
// Do what ever you want to create the right url
jsonRule.href = jsonRule.TimeSent;
return jsonRule;
}));
Then, in your template:
<div data-bind="with: $parent.entity">
<a data-bind="text: timeSentLabel,
attr: {href: href}"></a>
</div>';
Which is defined in js:
var timeSentTemplate = '<div data-bind="with: $parent.entity"><a data-bind="text: timeSentLabel, attr: {href: href}"></a></div>';
var columnDefs = [
{ cellTemplate: timeSentTemplate, /* etc. */ }
];
I hope I finally got your question correctly...
(https://plnkr.co/edit/93ucvDLk5bUFtU4dB1vn?p=preview, moved some stuff around)
Previous, more general answer:
When you create a knockout binding, knockout automatically wraps the second part of the binding in a function. For example:
data-bind="text: myTextObservable"
Is processed as:
text: function (){ return myTextObservable }
Additionally, knockout uses this function to create a computedObservable. This will create a subscription to any observable used inside the function, making sure the data-bind is re-evaluated if any of them changes.
This means that in your case, you can define your format rule inside your data-bind like so (assuming timeSent is an observable`):
data-bind="text: moment($parent.entity.timeSent()).format('DD/MM/YYYY h:mm a') "
Knockout will see that the timeSent observable is called and make sure the whole binding gets updated correctly. Here's an example:
var date = ko.observable(new Date());
var addDay = function() {
date(moment(date())
.add(1, "day")
.toDate()
);
};
ko.applyBindings({
date: date,
addDay: addDay
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<strong>The "raw" observable</strong>
<div data-bind="text: date"></div>
<br/>
<strong>A "computed" text defined in the data-bind</strong>
<div data-bind="text: moment(date()).format('DD-MM-YY')"></div>
<button data-bind="click:addDay">add a day</button>
My advice however is to create a separate computed observable inside your viewmodel. After all, this is what viewmodels are meant to do, and it will help you out a great deal when fixing bugs. I.e.:
// Add to your entity view model:
this.timeSentLabel = ko.computed(function() {
return moment(this.timeSent())
.format('DD/MM/YYYY h:mm a');
}, this);

Convert value into lower case before knockout binding

Demo Here
I bound a label with knockoutjs. The value bound always should be in lower case. While it will remain in uppercase in js model. How to do this ?
Javascript
var model = {
name:ko.observable("Test")
}
ko.applyBindings(model);
HTML
<label data-bind="text:name">
you just need to use toLowerCase in the view
view :
<div class='liveExample'>
<p> name: <label data-bind='text: name().toLowerCase()'></label></p>
</div>
<b>Original Value:
<pre data-bind="text:ko.toJSON($data,null,2)"></pre>
sample working fiddle here
It's unclear what you want to do, in particular when the value is coming from the textarea, but you can probably do whatever it is using a writable computed:
model.lowerName = ko.computed({
read: function() {
return model.name().toLowerCase();
},
write: function(newValue) {
// ...save this however it is you want to save it...
}
});
HTML:
<input data-bind="value:lowerName">
Re your updated question: Your update completely changes the question. If you don't need updates from the element and are only showing what's in name, you have two options:
A read-only computed:
model.lowerName = ko.pureComputed(function() { return model.name().toLowerCase(); });
HTML:
<label data-bind="text:lowerName"></label>
Just do it in the binding:
<label data-bind="text:name().toLowerCase()"></label>

Kendo Grid: how to get the selected item from a Combobox cell template when using with Angular

I have a Kendo grid which I am using within Angular, and have a field with a combo box, that has the editor set to the following function...
function comboCellTemplate(container, options) {
var input = $('<input name="' + options.field + '" />')
input.appendTo(container)
var combobox = input.kendoComboBox({
autoBind: true,
filter: "contains",
placeholder: "select...",
suggest: true,
dataTextField: "description",
dataValueField: "code",
dataSource: data,
});
And data is a list of simple json objects...
[
{code: 'code1', description: 'desc1'}
{code: 'code2', description: 'desc2'}
[
Each field in the grid data is bound to the same objects (ie with a code and description field)
I a previous post, to get sorting and filtering working I need to bind a field to the display field...
{
field: "Category.description",
title: "Category",
editor: comboCellTemplate,
template: "#=Category.description#"
},
When I do this, the combo box seems to set the field of the grid to the code.
How can I get this to set the grid data to the whole data object (ie the {code, description})
I have tried adding a on - change handler to do this
input.on('change', function () {
var val = input.val();
//var dataItem = input.dataItem();
options.model.set(options.field, val + 'xx');
});
but can't see how to get the "selected Item" from the combo
I don't seem to be able to find this in the help (in particular when using Angular)
Any help here would be greatly appreciated.
regards, Peter
I think you can simply add a change handler to the editor and set it from there:
function comboCellTemplate(container, options) {
var input = $('<input name="' + options.field + '" />')
input.appendTo(container)
var combobox = input.kendoComboBox({
autoBind: true,
filter: "contains",
placeholder: "select...",
suggest: true,
dataTextField: "description",
dataValueField: "code",
dataSource: data,
change: function () {
options.model.set(options.field, this.dataItem());
}
});
}
Ok, I think I have got to the bottom of this (after lots of diving through the doco)
I could get everything to work after I discovered that you can give a column a "magical" compare function.
So using this, my field can go back to binding to the whole json object ..
and add the sortable as follows...
{
field: "Category",
title: "Category",
editor: comboCellTemplate,
template: "#=Category.description#",
sortable:{
compare: function (a, b){
return a.Category.description.localeCompare(b.Category.description);
}
},
Now everything works exactly as I expect, and I don't need to do anything extra in the combobox. I hope this ("simple when you know how") tip can save someone else all the time it took me to find it.

How to use function in Kendo Grid Column Template with AngularJS

I have a column in a Kendo grid that I want to perform some specific logic for when rendering, and am using Angular. I have the grid columns set up using the k-columns directive.
After looking at the documentation, it seemed simple: I could add the template option to my column, define the function to perform my logic, and pass the dataItem value in. What I have looks something like this:
k-columns='[{ field: "Name", title: "Name",
template: function (dataItem){
// Perform logic on value with dataItem.Name
// Return a string
}
}]'
However, running this causes a syntax error complaining about the character '{' that forms the opening of the block in my function.
I have seen several examples of defining a template function in this format. Is there something else that needs to be done for this to work? Am I doing something incorrectly? Is there another way of defining the template as a function and passing the column data to it? (I tried making a function on my $scope, which worked, except I couldn't figure out how to get data passed into the function.)
Thank you for your help.
It appears that defining a column template in this fashion isn't supported when using AngularJS and Kendo. This approach works for projects that do not use Angular (standard MVVM), but fails with its inclusion.
The workaround that a colleague of mine discovered is to build the template using ng-bind to specify a templating function on the $scope, all inside of a span:
template: "<span ng-bind=templateFunction(dataItem.Name)>#: data.Name# </span>"
This is the default column templating approach that is implemented by Telerik in their Kendo-Angular source code. I don't know yet if the data.Name value is required or not, but this works for us.
Warning: Don't have access to Kendo to test the code at the moment, but this should be very close
In your case, you are assigning a a string to the value of k-columns and that string contains the the word function and your curly brace {
You need to make sure the function gets executed ... something like this:
k-columns=[
{
field: "Name",
title: "Name",
template: (function (dataItem){
// Perform logic on value with dataItem.Name
// Return a string
}())
}
];
Note the difference:
We create an object -- a real honest-to-goodness object, and we use an IIFE to populate the template property.
Maybe, it will be useful for someone - this code works for me too:
columns: [
{
field: "processed",
title:"Processed",
width: "100px",
template: '<input type="checkbox" ng-model="dataItem.processed" />'
},
and you get the two-way binding with something like this:
<div class="col-md-2">
<label class="checkbox-inline">
<input type="checkbox" ng-model="vm.selectedInvoice.processed">
processed
</label>
</div>
This can be done via the columns.template parameter by supplying a callback function whose parameter is an object representing the row. If you give the row a field named name, this will be the property of the object you reference:
$("#grid").kendoGrid({
columns: [ {
field: "name",
title: "Name",
template: function(data) {
return data.name + "has my respect."
}
}],
dataSource: [ { name: "Jane Doe" }, { name: "John Doe" } ]
});
More information is available on Kendo's columns.template reference page.
After hours of searching. Here is the conclusion that worked:
access your grid data as {{dataItem.masterNoteId}} and your $scope data as simply the property name or function.
Example
template: '<i class="fa fa-edit"></i>',
I really hope this safes somebody life :)
just use like my example:
}, {
field: "TrackingNumber",
title: "#T("Admin.Orders.Shipments.TrackingNumber")",
//template: '<a class="k-link" href="#Url.Content("~/Admin/Shipment/ShipmentDetails/")#=Id#">#=kendo.htmlEncode(TrackingNumber)#</a>'
}, {
field: "ShippingMethodName",
title: "#T("Admin.Orders.Shipments.ShippingMethodName")",
template:function(dataItem) {
var template;
var ShippingMethodPluginName = dataItem.ShippingMethodPluginName;
var IsReferanceActive = dataItem.IsReferanceActive;
var ShippingMethodName = dataItem.ShippingMethodName;
var CargoReferanceNo = dataItem.CargoReferanceNo;
var ShipmentStatusId = dataItem.ShipmentStatusId;
if (ShipmentStatusId == 7) {
return "<div align='center'><label class='label-control'><b style='color:red'>Sipariş İptal Edildi<b></label></div>";
} else {
if (ShippingMethodPluginName == "Shipping.ArasCargo" || ShippingMethodPluginName == "Shipping.ArasCargoMP") {
template =
"<div align='center'><img src = '/content/images/aras-kargo-logo.png' width = '80' height = '40'/> <label class='label-control'><b>Delopi Aras Kargo Kodu<b></label>";
if (IsReferanceActive) {
template =
template +
"<label class='label-control'><b style='color:red; font-size:20px'>"+CargoReferanceNo+"<b></label></div>";
}
return template;
}

Categories

Resources