KendoUI: binding view model to datasource change - mvvm

I have an observable object which defines a pointer to a datasource binded to a grid, and a custom field which should return an aggregate value I declared in the datasource.
I would like to bind the second field ("totAmount") to a custom HTML element.
I do not understand how to update its value: when I call the "read()" method of the datasource shouldn't the binded value also be updated on the interface? Does it work only with "primitive" model fields?
=== JAVASCRIPT ===
var vm = kendo.observable({
gridDatasource: new kendo.data.DataSource({ ... }),
totAmount: function() {
var ds = this.get("gridDatasource");
var value = (ds.aggregates()) ? ds.aggregates().totAmount : 0;
return value;
}
});
=== HTML ===
<span data-bind="text: totAmount"></span>

My previous answer was not totally correct: it binds the model update on grid change (on each row selection). It is better to bind it to the "change" event of the datasource:
=== JAVASCRIPT ===
var vm = kendo.observable({
gridDatasource: new kendo.data.DataSource({ ... }),
totAmount: 0
});
vm.gridDatasource.bind("change", function(e) {
vm.set("totAmount", this.aggregates().totAmount);
});
=== HTML ===
<span data-bind="text: totAmount"></span>

So far I have found a solution similar to my previous post (bind HTML elements to grid selected row/dataItem), setting the value in the "change" event of the grid binded to the datasource:
=== JAVASCRIPT ===
var vm = kendo.observable({
gridDatasource: new kendo.data.DataSource({ ... }),
totAmount: 0
});
$("#grid").kendoGrid({
change: function(e) {
vm.set("totAmount", this.dataSource.aggregates().totAmount);
}
});
=== HTML ===
<span data-bind="text: totAmount"></span>

Related

Smart table's property initiallyVisibleFields + ODataModel

I used SmartTable with the property initiallyVisibleFields. I bound ODataModel to it. The problem is when I want to show all fields of ODataModel, e.g. after I click on SmartTable's row and try to display it in the dialog. I just see fields from initiallyVisibleFields property. It looks like ODataModel is filtered with initiallyVisibleFields property.
I was thinking about JSONModel where I put copy of ODataModel before it is bind to SmartTable, but I am planning to use SmartFilterBar, so index of shown data in the table will be changed after filtering. So I can not simply pull data from JSONModel. I can still filter data from JSONModel based on the fields I get from
ODataModel filtered with initiallyVisibleFields but there I can still get different data, because there can be differences in the fields which are hidden.
Please, can you advice me how to solve this issue?
Thanks for any tips.
...
return Controller.extend("ABC.View1", {
oDialog: null,
onInit: function() {
var oModel, oView;
oModel = new ODataModel("/sap/opu/odata/sap/ABC/", {
useBatch: false
});
oView = this.getView();
oView.setModel(oModel);
this._createSmartTable();
},
_createSmartTable: function() {
var oSmartTable = new SmartTable('idSmartTable',{
entitySet: "ABCListSet",
tableType: "ResponsiveTable",
sStyleClass: "sapUiResponsiveContentPadding",
initiallyVisibleFields: "A,B,C,D",
showRowCount: false,
enableAutoBinding: true,
demandPopin: false,
useVariantManagement: false,
useExportToExcel: false,
useTablePersonalisation: true,
});
// Register event row click
var that = this;
var oTable = oSmartTable.getTable();
oSmartTable.attachDataReceived(function() {
var aItems = oTable.getItems();
if (aItems.length === 0) return;
$.each(aItems, function(oIndex, oItem) {
oItem.detachPress(that._createDialog);
oItem.setType("Active");
oItem.attachPress(that._createDialog);
});
});
var oVBox = new VBox();
oVBox.addItem(oSmartTable);
var oPage = this.getView().byId("idPage");
oPage.addContent(oVBox);
},
_createDialog: function(oEvent) {
//HERE I the oEvent has data filtered by initiallyVisibleFields property of Smarttable.
},
});
...
Do I understand you correctly that you want to show the complete entry in a dialog? The SmartTable uses $select statements to only load the fields of an entity that are also shown in the table. If you want to load all, I think you should add them in the requestAtLeast property.

Equivalent document.querySelector inside Mutation Observer dynamic elements

I'm using Mutation Observer to listen to the new added elements and it's working fine for all elements but for Switchery jQuery Plugin it doesn't because Switchery get element by [document.querySelector]
This is my code...
MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
var observerjQueryPlugins = function (repeaterWrapper) {
_.each(repeaterWrapper, function (repeaterItem, index) {
var jq_nodes = $(repeaterItem.addedNodes);
jq_nodes.each(function () {
// Color Picker (Working Good)
$(this).find('.element-wrapper.element-wpcolor .color-picker').wpColorPicker();
// Switchery using document.querySelector and i need to know the
// equivalent way to do it inside this loop .. like that
// Of course this code is WRONG
sw_current = $(this).find('.switchery-element');
var switchery = new Switchery( sw_current, {
disabled: false,
size: '',
color: '#8ce196',
secondaryColor: '#ddd',
jackColor: '#fff',
jackSecondaryColor: '#fff'
});
});
});
}
new MutationObserver(observerjQueryPlugins).observe(document.body, {
childList: true,
subtree: true,
attributes: false,
characterData: false
});
Thanks for your help.
It seems that Switchery is not a jQuery Plugin. That's why the sample code in GitHub uses document.querySelector to acquire element to apply it.
As you use jQuery to find elements, you need to use jQuery.each in order to process every DOM element for Switchery.
The following is an example to find element by jQuery and apply Switchery to each element. so, do the similar thing after sw_current = $(this).find('.switchery-element'); in your code.
$(function() {
sw_current = $(this).find('.switchery-element');
sw_current.each(function() {
var switchery = new Switchery(this);
})
});
#import url("http://abpetkov.github.io/switchery/dist/switchery.min.css");
<input type="checkbox" class="switchery-element" checked />Check 1
<p/>
<input type="checkbox" class="switchery-element" checked />Check 2
<p/>
<input type="checkbox" class="switchery-element" checked />Check 3
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://abpetkov.github.io/switchery/dist/switchery.min.js"></script>

kendo bind HTML elements to grid selected row/dataItem

I have the following situation (using KendoUI):
I have a grid binded to a datasource.
When I select a row in the grid I invoke its "change" event to get the selected dataItem e show its values through other HTML elements.
Something like the following:
$("grid-element").kendoGrid({
change: setElements
});
function setElements() {
var grid = $("#grid-element").data("kendoGrid");
var selectedItem = grid.dataItem(grid.select());
$("#span-field1").text(selectedItem.field1);
$("#span-field2").text(selectedItem.field2);
$("#span-field3").text(selectedItem.field3);
}
My question is: is it possibile to achieve the same through MVVM or a better KendoUI model binding solution?
So far I have found the following solution:
=== JAVASCRIPT ===
var vm = kendo.observable({
gridSelectedItem: null,
_field1: function() {
return this.get("gridSelectedItem.field1");
},
_field2: function() {
return this.get("gridSelectedItem.field2");
}
});
$("#grid-element").kendoGrid({
change: function(e) {
var selectedItem = this.dataItem(this.select());
vm.set("gridSelectedItem", selectedItem);
}
});
=== HTML ===
<span data-bind="text: _field1"></span>
<span data-bind="text: _field2"></span>
Is there a better way?
Indeed there you are on the right track,
Here is what I can suggest you to try:
=== JAVASCRIPT ===
var vm = kendo.observable({
gridSelectedItem: null
});
$("#grid-element").kendoGrid({
change: function(e) {
var selectedItem = this.dataItem(this.select());
vm.set("gridSelectedItem", selectedItem);
}
});
=== HTML ===
<span data-bind="text: gridSelectedItem.field1"></span>
<span data-bind="text: gridSelectedItem.field2"></span>
It should be slightly more compact.

Mootools stop form submit method

I don't want to use an <input type=submit /> button to submit a form and I am instead using an <a> element. This is due to styling requirements. So I have this code:
myButton.addEvent('click', function() {
document.id('myForm').submit();
});
However, I have also written a class that improves and implements the placeholder attribute on inputs and textareas:
var FDPlaceholderText = new Class({
Implements: Events,
initialize: function() {
var _self = this;
var forms = document.getElements('form');
forms.each(function(form) { // All forms
var performInit = false;
var i = 0;
var ph = [];
form.getElements('input, textarea').each(function(el) { // Get form inputs and textareas
if (el.getProperty('placeholder') != null) { // Check for placeholder attribute
performInit = true;
ph[i] = _self.initPlaceholder(el); // Assign the placeholder replacement to the elements
}
i ++;
});
if (performInit) {
_self.clearOnSubmit(form, ph);
}
});
},
clearOnSubmit: function(form, ph) {
form.addEvent('submit', function(e) {
ph.each(function(el) {
if (el.value == el.defaultValue) {
el.value = '';
}
});
});
},
initPlaceholder: function(el) {
el.defaultValue = el.getProperty('placeholder');
el.value = el.getProperty('placeholder');
el.addEvents({
'focus': function() {
if (el.value == el.defaultValue) el.value = '';
},
'blur': function() {
if(el.value.clean() == ''){
el.value = el.defaultValue;
}
}
});
return el;
}
});
window.addEvent('domready', function() {
new FDPlaceholderText();
});
The above class works great if a form is submitted using an actual <input type=submit /> button: it listens for a submit and clears the inputs values if they are still the default ones therefore validating that they are essentially empty.
However, it seems that because I am submitting one of my forms by listening to a click event on an <a> tag the form.addEvent('submit', function(e) { isn't getting fired.
Any help is appreciated.
well you can change the click handler to fireEvent() instead of call the .submit() directly:
myButton.addEvent('click', function() {
document.id('myForm').fireEvent('submit');
});
keep in mind a couple of things (or more).
placeholder values to elements that lack placeholder= attribute is pointless
if you detect placeholder support, do so once and not on every element, it won't change suddenly midway through the loop. you can go something like var supportsPlaceholder = !!('placeholder' in document.createElement('input')); - remember, there is no need to do anything if the browser supports it and currently, near enough 60% do.
you can otherwise do !supportsPlaceholder && el.get('placeholder') && self.initPlaceholder(el); - which avoids checking attributes when no need
when the form is being submitted you really need to clear placeholder= values in older browser or validation for 'required' etc will fail. if validation still fails, you have to reinstate the placeholder, so you need a more flexible event pattern
avoid using direct references to object properties like el.value - use the accessors like el.get('value') instead (for 1.12 it's getProperty)
for more complex examples of how to deal with this in mootools, see my repo here: https://github.com/DimitarChristoff/mooPlaceholder
This is because the submit() method is not from MooTools but a native one.
Maybe you can use a <button type="submit"> for your styling requirements instead.

getting class attr in jquery

I have some divs that are generated dynamically with content. I add the content id to the class for the div like so:
<div class="div-1"></div>
<div class="div-3"></div>
<div class="div-6"></div>
<div class="div-8"></div>
How do I select the id for a div because I need it as a param to send via ajax. e.g. I need to get the 1 when I click on the 1st div, 3 when I click on 2nd and so on
var id = $(this).attr('class').replace('div-', '');
Or even simple
var id = this.className.replace('div-', '');
Where this points to the dom element you click on inside the click handler.
//Here instead of document it is better to specify a parent container of all divs
$(document).on('click', '[class^="div-"]', function(){
var id = this.className.replace('div-', '');
});
Try this, and remember changing "div" for your selector:
$(document).on("click", "div", function() {
var class_elem = $(this).attr("class").split("-");
var n = class_elem[1]; // This is your number
});
The correct jQuery syntax is:
$("div").click( function() {
var id = $(this).attr('class').replace('div-', '');
});