问题
A few days before I asked this question and got a really cool answer. Hereafter I wonder if I can use my custom widget as I use all standart kendo components by mvvm convention. And what parts of custom widget do I have to edit? For example:
<div id="dropdowns" data-role="linkeddropdowns" data-period="YEAR"
data-bind="year: selectedYear"></div>
Thanks,
回答1:
I think you may run into problems with the internal view model approach because Kendo UI tends to not be good about nesting view model bindings. As far as I know, all Kendo UI widgets create their internal widgets in code because of that.
Side note: in your widget, you were using DOM ids for the dropdown elements - this would create duplicates if you were to create multiple of your widgets on the same page. It's better to use classes in that case.
To enable a year
binding, you'll need a custom binder, which might look something like this:
kendo.data.binders.widget.year = kendo.data.Binder.extend({
init: function (element, bindings, options) {
kendo.data.Binder.fn.init.call(this, element, bindings, options);
var that = this;
that.element.bind("change", function () {
that.change(); //call the change function
});
},
refresh: function () {
var that = this,
value = that.bindings.year.get();
this.element.setYear(value);
},
change: function () {
var value = this.element.getYear();
this.bindings.year.set(value);
}
});
This would work with a widget that provides these accessors:
getYear: function () {
return this._getWidget("year").value();
},
setYear: function (value) {
this._getWidget("year").value(value);
console.log(this._getWidget("year"));
}
Complete widget example (note that it's not fully implemented - it only takes into account the year binding and the period setting):
(function ($) {
var kendo = window.kendo,
ui = kendo.ui,
Widget = ui.Widget,
periods = [
{ text: "PERIOD: YEAR", value: "YEAR" },
{ text: "PERIOD: QUARTER", value: "QUARTER" }
],
quarters = [
{ text: "1. Quarter", value: 1 },
{ text: "2. Quarter", value: 2 },
{ text: "3. Quarter", value: 3 },
{ text: "4. Quarter", value: 4 }
],
years = [2011, 2012, 2013, 2014];
var LinkedDropDowns = Widget.extend({
init: function (element, options) {
var that = this,
periodOption = $(element).data("period");
if (periodOption) {
this.options.period = periodOption;
}
Widget.fn.init.call(that, element, options);
that._create();
// make sure view state is correct depending on selected period
this._getWidget("period").trigger("change");
},
options: {
name: "LinkedDropDowns",
period: "YEAR",
periods: periods,
year: 2011,
years: years,
quarter: 1,
quarters: quarters,
selectedYear: 2011
},
onPeriodChange: function (e) {
switch (e.sender.value()) {
case "YEAR":
$(this._getWidget("year").wrapper).show();
$(this._getWidget("quarter").wrapper).hide();
break;
case "QUARTER":
$(this._getWidget("year").wrapper).show();
$(this._getWidget("quarter").wrapper).show();
break;
default:
break;
}
},
onChange: function () {
// trigger change so the binder knows about it
this.trigger("change", { sender: this });
},
_getWidget: function (name) {
var el = $(this.element).find("input." + name).first();
return el.data("kendoDropDownList");
},
_create: function () {
var that = this;
// create dropdowns from templates and append them to DOM
that.periodDropDown = $(that._templates.periodDropDown);
that.yearDropDown = $(that._templates.yearDropDown);
that.quarterDropDown = $(that._templates.quarterDropDown);
// append all elements to the DOM
that.element.append(that.periodDropDown)
.append(that.yearDropDown)
.append(that.quarterDropDown);
$(this.element).find(".period").kendoDropDownList({
dataTextField: "text",
dataValueField: "value",
value: this.options.period,
change: this.onPeriodChange.bind(that),
dataSource: this.options.periods
});
$(this.element).find(".year").kendoDropDownList({
dataSource: this.options.years,
change: this.onChange.bind(this)
});
$(this.element).find(".quarter").kendoDropDownList({
dataTextField: "text",
dataValueField: "value",
dataSource: this.options.quarters
});
},
_templates: {
periodDropDown: "<input class='period' />",
yearDropDown: "<input class='year' style='width: 90px' />",
quarterDropDown: "<input class='quarter' style='width: 110px' />"
},
getYear: function () {
return this._getWidget("year").value();
},
setYear: function (value) {
this._getWidget("year").value(value);
console.log(this._getWidget("year"));
}
});
ui.plugin(LinkedDropDowns);
})(jQuery);
(demo)
回答2:
No additional coding to the widget is required. To enable the widget for declarative initialization, you can do the following:
HTML
<div id="dropdowns" data-role="linkeddropdowns" data-period="QUARTER" data-year="2014"></div>
These data attributes will override the default options of "YEAR" and "2011" in the widget.
JavaScript
(function() {
kendo.init($('body'));
})();
Instead of calling $('#dropdowns').kendoLinkedDropDowns()
, just call kendo.init()
and the widget takes care of binding itself.
Here is the updated working JSBin example.
来源:https://stackoverflow.com/questions/24933598/mvvm-support-for-custom-kendo-ui-widget