Kendo UI: How to bind Kendo UI hierarchical datagrid detailInit event using MVVM (data-attribute) - mvvm

I am constructing a hierarchical datagrid using Kendo UI and I am using MVVM methodology for widget binding.
Here is the DEMO of the kind of hierarchical grid I want to make. But the example here uses jQuery and not MVVM.
How can I bind the detailInit event to my viewModel using data attributes using MVVM?
I want to bind the event using the below code but it is not working:
JS:
var viewModel = kendo.observable({
......
..........
dataGridDetailInit: function (e) {
//Here I want to catch the detailInit event of the dataGrid
},
..........
......
});
HTML (Kendo template):
<!-- Datagrid -->
<div data-role="grid"
data-columns="[
{'field':'FullName', 'title':'Full Name'},
{'field':'Email', 'title':'Email'},
{'field':'HomeTel', 'title':'HomeTel'},
{'field':'Mobile', 'title':'MobileTel'},
{'field':'Contact_Type', 'title':'Contact Type'},
]"
data-bind ="source: address_book_datagrid_observable.datasource,
events: {
detailInit: dataGridDetailInit
}"
data-pageable='{
refresh: false,
pageSizes: true,
buttonCount: 5,
}'
data-navigatable = "true"
data-resizable = "true"
data-no-records= "true"
data-messages = '{
noRecords: "There is no data to be displayed"
}'
>
</div>

Ok, so while researching I came across this link.
On this issue, an engineer from Telerik asserted this:
All Kendo widgets can be configured via data attributes. Building a
hierarchical grid declaratively is supported too, however please have
in mind that: detailInit event should not be bound through the events
binding but via data-attribute.
Here is the example of how the event binding could be accomplished.
The right way to bind detailInit event to viewModel using MVVM (data attibute is) using data-detail-init as below:
<!-- Datagrid -->
<div data-role="grid"
data-columns="[
{'field':'FullName', 'title':'Full Name'},
{'field':'Email', 'title':'Email'},
{'field':'HomeTel', 'title':'HomeTel'},
{'field':'Mobile', 'title':'MobileTel'},
{'field':'Contact_Type', 'title':'Contact Type'},
]"
data-bind ="source: viewModel.datasource"
data-detail-init="viewModel.dataGridDetailInit"
data-pageable='{
refresh: false,
pageSizes: true,
buttonCount: 5,
}'
data-navigatable = "true"
data-resizable = "true"
data-no-records= "true"
data-messages = '{
noRecords: "There is no data to be displayed"
}'
>
</div>

Related

Angular 2 / PrimeNG - Expression has changed after it was checked. Binding NgModel on last invalid form control

I'm having a problem where when the very last element in my form has a value bound to it the error "Expression has changed after it was checked." is thrown.
I will preface by saying this is based off of the Angular 2 website example here -
https://angular.io/docs/ts/latest/cookbook/dynamic-form.html#!#top
The way my app works is first I build a dynamic form with controls in my form component based off a model.
My form components html loops the questions in the model like so
<form *ngIf="showForm" [formGroup]="formGroup">
<!-- questions-->
<div *ngIf="questions.length > 0">
<div *ngFor="let question of questions">
<question [question]="question" [formGroup]="formGroup"></question>
</div>
</div>
<button pButton type="submit" label="Submit" icon="fa-check-circle-o" iconPos="left"
[disabled]="!formGroup.valid" (click)="submitFinalForm()"></button>
</form>
Below is the question component html that uses the data that was passed in from the form component to display certain types of questions via ngSwitch
<label [attr.for]="question.field">
{{ question.question }}
</label>
<div [ngSwitch]="question.type">
<!-- Radio / Checkbox -->
<radio-checkbox-question *ngSwitchCase="1" [formGroup]="formGroup" [question]="question"></radio-checkbox-question>
</div>
Finally here is the radio-checkbox-question component
<div *ngIf="showQuestion" [formGroup]="formGroup">
<!-- Radio -->
<div *ngIf="model.radiocheckbox == 'radio'">
<div *ngFor="let label of model.labels; let i = index;">
<p-radioButton name="{{model.field}}"
value="{{i}}"
label="{{label}}"
formControlName="{{model.field}}"
[(ngModel)]="questionAnswerRadio"></p-radioButton>
</div>
</div>
</div>
Here is the actual component TS
import { Component, Input, OnInit } from "#angular/core";
import { FormGroup } from "#angular/forms";
import { RadioCheckboxQuestion } from "../Questions/radio.checkbox.question.model";
#Component({
selector: "radio-checkbox-question",
templateUrl: "radio.checkbox.component.html"
})
export class RadioCheckboxComponent implements OnInit {
#Input() question: any;
#Input() formGroup: FormGroup;
model: RadioCheckboxQuestion = new RadioCheckboxQuestion();
showQuestion: boolean = false;
questionAnswerRadio: string = "";
ngOnInit(): void {
// question essential properties
if (this.question.hasOwnProperty("field") && this.question["field"] &&
this.question.hasOwnProperty("labels") && this.question["labels"]) {
this.model.field = this.question["field"];
this.model.labels = this.question["labels"];
// assume always radio for debugging
this.model.radiocheckbox = "radio";
// set existing answer
if (this.question.hasOwnProperty("QuestionAnswer") && this.question["QuestionAnswer"]) {
if (this.model.radiocheckbox == "radio") {
this.questionAnswerRadio = this.question["QuestionAnswer"];
}
}
this.showQuestion = true;
}
}
}
I've also seen many SO issues like the following
Angular 2 dynamic forms example with ngmodel results in "expression has changed after it was checked" which basically state that [(ngModel)] should not be used with dynamic forms, but the primeNG documentation says the components can work with model driven forms and the only way to set the answer (that I know of) is [(ngModel)]. I believe what might happen here is since I set the only question in the formGroup to a value that the formGroup becomes valid in between the change detection and causes the error
Error in ./FormComponent class FormComponent - inline template:17:48 caused by: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'.
From your template it looks like you are using both model drive (formControlName)
and template driven (ngModel).
<p-radioButton name="{{model.field}}"
value="{{i}}"
label="{{label}}"
formControlName="{{model.field}}"
[(ngModel)]="questionAnswerRadio"></p-
<radioButton>
Please select one way and try again.
I suggest you to remove the [(ngModel)]
The only way i've found to get the change detection to be happy with my multi-nested components and primeNG was to implement full change detection manually. What that basically means was in every component I had to add something like the following
import ChangeDetectorRef
constructor(private change: ChangeDetectorRef)
{}
ngOnInit() {
// code here that inits everything
this.change.markForCheck();
}
Anything less then this caused the change detection errors to pop-up in different and unique ways in the components that used primeNG.

Reactjs together with TinyMCE editor code plugin

I'm using Reactjs together with the tinyMCE 4.1.10 html editor (together with the code plugin) and bootsrap css + js elements. A fairly working setup after a few quirks with the editor have been removed (manual destruction if the parent element unmounts)
Now the question: The textarea input of the code plugin does not receive any focus, click or key events and is basically dissabled. Setting the value via javascript works just fine, but it does not function as a normal html input.
It is opened as the following:
datatable as react components
opens bootsrap modal as react component
initializes tinymce on textareas inside of the modal
loads the code plugin (which itself then is not accepting any kind of input anymore)
My initilization of the editor looks like this:
componentDidMount: function(){
tinymce.init({
selector: '.widget-tinymce'
, height : 200
, resize : true
, plugins : 'code'
})
}
My guess would be, that react.js is somehow blocking or intersepting the events here. If I remove the react modal DOM, it is just working fine.
Does anybody has an idea, what is causing this or how to simply debug it further?
Thx a lot!
if you are using Material UI. disable Material UI Dialog's enforce focus by adding a prop disableEnforceFocus={true} and optionally disableAutoFocus={ true}
What does your html/jsx look like in your component?
My guess is that react might be treating your input as a Controlled Component
If you're setting the value attribute when you render, you'll want to wait, and do that via props or state instead.
Alright, so it turned out that bootstrap modals javascript is somehow highjacking this. In favor of saving some time I decided not to dig realy into this but just to create my own modal js inside of the jsx.
Aparently there is also React Bootstrap, but it looks at the moment to much beta for me in order to take this additional dependency in.
The final code looks like this, in case it becomes handy at some point:
Modal = React.createClass({
show: function() {
appBody.addClass('modal-open');
$(this.getDOMNode()).css('opacity', 0).show().scrollTop(0).animate({opacity: 1}, 500);
}
, hide: function(e){
if (e) e.stopPropagation();
if (!e || $(e.target).data('close') == true) {
appBody.removeClass('modal-open');
$(this.getDOMNode()).animate({opacity: 0}, 300, function(){
$(this).hide();
});
}
}
, showLoading: function(){
this.refs.loader.show();
}
, hideLoading: function(){
this.refs.loader.hide();
}
, render: function() {
return (
<div className="modal overlay" tabIndex="-1" role="dialog" data-close="true" onClick={this.hide}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button type="button" className="close" onClick={this.hide} data-close="true" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 className="modal-title" id="myModalLabel">{this.props.title}</h4>
</div>
<div className="modal-body" id="overlay-body">
{this.props.children}
<AjaxLoader ref="loader"/>
</div>
</div>
</div>
</div>
);
}
})
Best wishes
Andreas
Material UI: disable Dialog's enforce focus by adding a prop disableEnforceFocus={true} and optionally disableAutoFocus={ true}

How to bind Kendo UI AutoComplete values to URLs?

How to bind Kendo UI AutoComplete values to URLs?
I use the open source version; Kendo UI Core.
You can use template and wrap your content inside an anchor tag.
var autocomplete = $("selector").kendoAutoComplete({
minLength: 1,
dataTextField: "Name",
template: '#: Name #</span>',
dataSource: {//your data source details
}
}
}).data("kendoAutoComplete");
});

Kendo UI: How to set the value of a tooltip with a MVVM binding

In Kendo UI, I have a tooltip declaratively defined inside a view:
<span data-bind="events: { show: onShow }"
data-role="tooltip"
data-auto-hide="true"
data-position="top">?</span>
Normally the content of the tooltip would be attached via the title attribute, or when attaching the tooltip procedurally, via the content property. But here, the content should be fetched out of the model.
So I'm looking for the equivalent of data-bind="text: contents for the Kendo Tooltip.
Can be done by creating a small custom binder.
kendo.data.binders.widget.tooltip = {
value: kendo.data.Binder.extend({
refresh: function() {
var value = this.bindings["value"].get();
var tooltip = this.element;
tooltip.element.attr("title",value);
}
})
};
Here is a live demo.

Kendo UI Grid popup editing with MVVM

I am using Kendo UI Grid and I have configured it to use popup editing with custom template
<script id="popup_editor" type="text/x-kendo-template">
<div id="editor">
<div class="k-edit-label">
<label for="Type">Type</label>
</div>
<select data-role="dropdownlist" data-value-field="Type" data-text-field="Type"
data-bind="source: typeSource, value: selectedProduct"></select>
<div class="k-edit-label">
<label for="Type">Option</label>
</div>
<select data-role="dropdownlist" data-value-field="Option" data-text-field="Option"
data-bind="source: productsSource.Options, value: selectedOption"></select>
</div>
</script>
This is my ViewModel:
function ViewModel() {
var getTypesUrl = "/Controller/Action";
var viewModel = kendo.observable({
typeSource: new kendo.data.DataSource({
transport: {
read: {
url: getConditionTypesUrl,
dataType: "json"
},
},
batch: true,
schema: {
model: {
id: "Type"
}
}
}),
selectedType: null,
selectedOption: null
});
kendo.bind($("#editor"), viewModel);
}
ViewModel();
My action returns JSON.
The problem is that when I click on the "Add new record" button, there is no call to the getTypesUrl and the dropdownlist is not populated. The general idea is to have different options for different types and to populate the Option dropdownlist depending on the selected type. I believe, that the problem occurs because the editor is showed only when the button is clicked and the kendo can not create the bindings.
If the Drop down list is the same for each row get its values from the Data Source and store these in a variable in the page in JavaScript and point the Drop Down list at this new Data Source. Use some JavaScript to associate the id and name.
Alternatively if this is loaded based on some other logic implement a separate call to populate the Data source for the drop down list in your view model.
http://www.aspnetwiki.com/page:introduction-to-kendo-mvvm
http://www.aspnetwiki.com/page:kendo-mvvm-ui-grid
Further note your can write your template purely in JavaScript and bind this to the html, advantage of which is you can debug it and it can still be loaded by an ajax call later and it is likely going to be smaller.