Redefine data packet in Kendo UI grid edit popup - kendo-ui

I think this is an advance topic in Kendo UI.
I have a Kendo UI grid and I added a custom edit popup to update the data in the grid.
My data packet like this :
{
fieldOne : "valueOne";
fieldTwo : "valueTwo";
fieldThree : [{a : "someValue", b : "someValue"}]
}
In edit popup I will edit this data.
But I have a new requirement that add a new value to fieldThree.
My new Data packet will look like this...
{
fieldOne : "valueOne";
fieldTwo : "valueTwo";
fieldThree : [{a : "someValue", b : "someValue"},{a : "someValue", b : "someValue"}]
}
What I have done is I made a custom popup and custom fields for that.
But my question is how I redefine the data packet to above one ??
In Kendo UI it will only update existing values...

The edit event gets fired when you click the button to open the popup and has access to the model.
You may be able to do something like this:
edit: function(e)
{
e.model.fieldThree.push({
a: "someValue",
b: "someValue"
});
}
That kind of what you are trying to do?

Related

OpenLayers events issue, featureover and onselect

I have a strange problem with the use of vector layers events.
Here is snipped of my code:
var options = {
projection : "EPSG:3857",
displayProjection : "EPSG:4326",
numZoomLevels : 18,
//after delete this part below of option everything works good
eventListeners: {
featureover: function(e) {
document.getElementById("output").innerHTML="ok';
}}};
map = new OpenLayers.Map('map', options);
w_parcels = new OpenLayers.Layer.Vector("PARCELS", {
styleMap : style_parcels,
projection : "EPSG:3857",
strategies : [ new OpenLayers.Strategy.Fixed() ],
protocol : new OpenLayers.Protocol.HTTP({
url : "parcels.php",
format : new OpenLayers.Format.GeoJSON()})
});
map.addLayers([osm,w_parcels]);
selectControl = new OpenLayers.Control.SelectFeature(w_parcels, {
clickout: false,
multiple: true,
onSelect : onFeatureSelect,
onUnselect : onFeatureUnselect,
toggleKey: "ctrlKey" // ctrl key removes from selection
});
selectControl.handlers.feature.stopDown = false;
map.addControl(selectControl);
selectControl.activate();
map.addControl(new OpenLayers.Control.ScaleLine());
function onFeatureSelect(feature) {
console.log('it works');
}
In this code event onselect dosen't work always when I click on feature on the layer(sometimes I have to do double click).
If I delete eventListeners from options , the onselect works perfect, I mean always when I click feature on the layer.
What is wrong in my code? Is the possibility to resolve this conflict betwween eventListeners an onselect?
Seems like, Event featureover masks the select control as that function will executes first while you select, as you must mouse over the Vector Layer for clicking it. But if the functionality is limited to select and mouse-over vector layer. Then you can use something like-
eventListeners: {
featureover: function(e) {
//behavior for hover events
},
featureout: function(e) {
//behavior for mouse out events
},
featureclick: function(e) {
//behavior for click events
}
}
Hope this helps.

CKEditor - Trigger dialog ok button

I'm using CKEditor and I wrote a plugin that pops up a the CKEditor dialog.
I need to re design the ok button and add to the footer more elements like textbox and checkbox but it's seems to be to complicated to do so, so I've hide the footer part and created a uiElement in the dialog content with all what I need but now what I want is to trigger the okButton in the hidden footer but I can't find a way to do it..
Anyone?!
There may be a better way, but here's how I'm doing it:
var ckDialog = window.CKEDITOR.dialog.getCurrent(),
ckCancel = ckDialog._.buttons['cancel'],
ckOk = ckDialog._.buttons['ok'];
ckOK.click();
The trick is to get the button and then use the CKEditor Button API to simulate the click. For some reason, I was unable to call dialog.getButton('ok') because getButton is undefined for some reason. My method digs into the private data, which I doubt is the best way to do it.
From the onShow event (when defining the dialog), I was able to get the ok button like the docs indicate:
onShow: function () {
var okBtn = this.getButton('ok');
...
}
Here's the Button API: http://docs.ckeditor.com/#!/api/CKEDITOR.ui.dialog.button, and you can access the dialog API there too (I'm assuming you've already been there!!!)
You might try to add this line in your plugin.js.
var dialog = this.getDialog();
document.getElementById(dialog.getButton('ok').domId).click();
In my custom plugin, i just hide the "ok" button instead of the whole footer.
Below is a part of my plugin.js statements.
{
type : 'fileButton',
id : 'uploadButton',
label : 'Upload file',
'for' : [ 'tab1', 'upload' ],
filebrowser :
{
action : 'QuickUpload',
onSelect : function(fileUrl, data){
var dialog = this.getDialog();
dialog.getContentElement('tab1','urlTxt').setValue(fileUrl);
document.getElementById(dialog.getButton('ok').domId).click();
}
}
}
btw, i'm using CKEditor 4.0 (revision 769d96134b)

Kendo UI grid - batch update not executed

I'm implementing a simple (at least ,that was the goal) Kendo UI grid that displays two columns: one holding a checkbox, bound to a boolean, and one holding a display name for the item. The checkbox column has a simple template, and the change() event of the checkbox is handled so that the model in the datasource gets updated. I have verified this, and it works.
The data source has been configured for batch, and defines a transport for read and update. Both call a function that perform the ajax call. As I said before, the read function is handled as expected. However, the update function defined on the transport is not. The sync() on the datasource is triggered with a simple button whose click event is hooked to a function that calls datasource.sync() (or grid.saveChanges()).
transport: {
read: function(options) {
return loadStuff(options);
},
update: function (options) {
return updateStuff(options);
}
}
When debugging in the Kendo UI code, it looks like the models attribute on the ModelSet is always empty, and therefore the sync() decides that there's nothing to sync. Anyone got a clue what is happening here?
UPDATE:
Looks like something may be wrong when handling the checkbox check / uncheck. Apparently I should use something like
$('#divGrid').on('click', '.chkbx', function() {
var checked = $(this).is(':checked');
var grid = $('#divGrid').data().kendoGrid;
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("Selected", checked);
});
Unfortunately, it looks like the set() method is not defined on the data item. When debugging, it only contains the data, and no Model object having the set() method.
UPDATE 2:
Tried wrapping the data returned from the ajax call in a model defined with Model.define(). That seems to solve the issue of the model not being dirty, as the _modified property on the model returns true. However, the models array in the ModelSet remains empty. Is this a bug in Kendo UI, or am I going the wrong way?
You don't actually need to bind to click event on the checkboxes.
I´ve posted an example on using it in JSFiddle where you can see it running. This example displays in a grid two columns: first text (tick) and second boolean rendered as a checkbox (selected); the update is batch (so, it's pretty close to what you have).
Questions to keep in mind are:
For displaying the checkbox while not in edit mode, you should define a template, something like this. You might realize that the checkbox is in disabled state by default since you want to edit it as other fields (selecting the cell first). This also guarantees that the model is correctly updated:
{
field : "selected",
title : "Selected",
template: "<input type='checkbox' name='selected' #= selected ? 'checked' : '' # disabled/>"
}
Define in the model that this field is boolean:
schema : {
id : "id",
model: {
fields: {
symbol : { type: "string" },
selected: { type: "boolean" }
}
}
},
Define the transport.update function, something like:
transport: {
read : function (operation) {
// Your function for reading
},
update: function (operation) {
// Display modified data in an alert
alert("update" + JSON.stringify(operation.data.models, null, 4));
// Invoke updating function
// that should ends with an operation.success(the_new_data)
// In this example just say ok
operation.success(operation.data.models)
}
}
EDIT: If you want to be able to modify the checkbox state without having to enter in edit mode first, you should:
Remove the disabled from the template:
{
field : "selected",
title : "Selected",
template : "<input type='checkbox' name='selected' #= selected ? 'checked' : '' #/>"
},
Then bind the click event on checkboxes to the following handler function:
$("#stocks_tbl").on("click", "input:checkbox", function(ev) {
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("selected", this.checked);
});
Where #stocks_tbl is the id of the div that contains the grid. You might see it running here.
NOTE: It's important the on with the three parameters for making it live

ExtJS MVC : how to remove handler from dynamic controller

I'm creating a dynamic controller, according to the new MVC pattern in ExtJS4 and ran into a small problem. I've used the this.control method to attach the controller to my view. When create the controller a second time (going back and forth in my navigation), I have attached them couple times. My question is : What is the best way to destroy a controller or to remove all the listeners that I've setup via the this.control command.
Thanks in advance
Chris
The code of my new controller looks like like :
I create the new controller like this:
var step1Controller = Ext.create("MyApp.controller.Step1Controller", {
application : this.application
});
step1Controller.init();
In in the init function of my controller I've attached my controller to the view like this:
init : function() {
this.addEvents(['step1completed','basecontructionaborted']);
this.setupScreenLayout();
this.getTmpConfiguredControlModelsStore().removeAll();
this.application.fireEvent("addBreadCrumb", "Inbetriebnahme");
this.application.fireEvent("addBreadCrumb", "Schritt 1/3");
this.control({
'#addmodelbutton' : {
click : this.onAddBtnClick
},
'#modelviewer' : {
modelselected : this.onPanelSelect
},
'#navigationcontainer #movemodelleftbutton' : {
click : this.onMoveModelLeftClick
},
'#navigationcontainer #continuestep2' : {
click : this.onContinueStep2Click
},
'#navigationcontainer #abortbutton' : {
click : this.onAbortButtonClick
}
});
console.log('[BaseConstruction | init] completed');
}
Old question, but I killed half a day on solving this, so I'll post how I was able to get around it. This question seems very similar to my own issue. Hope it's useful to someone else.
I am loading controllers/views dynamically, and all listeners were attached via the app.control inside of a controller's init(). Worked fine until I started destroying/initializing views repeatedly. The listeners remained on the views after view.destroy(), so initializing them later down the road caused those listeners (ie render, click, etc) to fire twice.
This solved it for me:
app.control({
'element': {
beforerender: {
fn: function(thing){
// beforerender stuff for thing
thing.on('select', function(this, record, item, index){
console.log('select fired');
});
},
single: true
},
}
});
Note the "single: true" that's attached to the 'beforerender'. That's the crucial part. All other listeners that were previously written like 'beforerender' were moved to inside of it with the .on().
Cheers!

Why does Ext.form.Field.setValue() not fire an event? How to "fix" it?

Why is it that Ext.form.Field's setValue does not fire an event to notify listeners it's value has changed? I know there is the change and select event for combobox but these only fire events on user interaction, what about when another component changes the value of a field? Let me explain by a situation i'm facing atm.
I'm currently working on a reusable fieldset component (lets call it ux.fieldset) with a combobox and another fieldset inside. The inner fieldset should be hidden/shown based on the selected value of the combobox.
I've registered a listener on the combobox which listens to the select event and when it fires just evaluates the selected value and show/hides the inner fieldset.
Then I add this ux.fieldset as a component to one of my forms.
Now when I do a loadRecord() on the form I would like the value of the inner combobox be re-evaluated so I can show/hide the inner fieldset of my component.
The code that does this evaluation should obviously be in the ux.fieldset since that contains the combobox and since it's reusable it would be wise to put it there (DRY).
Is there a preferred or better way to handle this scenario? I've pasted the code of my ux below in case anyone is confused by my explanation above.
Ext.ux.form.StatusFieldSet = Ext.extend(Ext.form.FieldSet, {
enablePublishFrom : false // Wether or not the option to (un)publish on a certain date should be visible, defaults to false
,item_store : false
,combo : false
,date_publish : false
,date_unpublish : false
,helpBox : {
xtype : 'box'
,autoEl : {cn: 'Help text<br />'}
}
,publishData_fieldset : false
,datePickerWidth : 60 // The width of the datepickers in the subfieldset
,initComponent : function(){
this.item_store = [['online', _('Gepubliceerd')]]; // Online
if(this.enablePublishFrom) {this.item_store.push(['pending', _('Publiceer op datum')]);} // Publish on date
this.item_store.push(['offline', _('Niet gepubliceerd')]); // Offline
this.combo = new Ext.form.ComboBox({
name : 'status'
,hideLabel : true
,displayField : 'txt'
,valueField : 'quicklink'
,hiddenName : 'status'
,value : 'online'
,forceSelection : true
,allowBlank : false
,editable : false
,triggerAction : 'all'
,mode : 'local'
,store : new Ext.data.SimpleStore({
fields : [ 'quicklink', 'txt' ]
,data : this.item_store
})
,listeners : {
scope : this
,select : function(combo, value, index) { // HERE I would like to add another listener that gets triggered when another value is selected or set through setValue()
this.showOnPending(value.data.quicklink);
}
}
});
this.date_publish = new Ext.form.DateField({
fieldLabel : _('Publiceer op')
,name : 'publish_date'
,format : 'd-m-Y'
,width : this.datePickerWidth
});
this.date_unpublish = new Ext.form.DateField({
fieldLabel : _('De-publiceer op')
,name : 'unpublish_date'
,format : 'd-m-Y'
,width : this.datePickerWidth
});
this.publishData_fieldset = new Ext.form.FieldSet({
autoHeight : true
,hidden : true
,anchor : '0'
,defaults : {
labelSeparator : ''
,anchor : '0'
}
,items : [ this.helpBox, this.date_publish, this.date_unpublish ]
});
// Config with private config options, not overridable
var config = {
items : [ this.combo, this.publishData_fieldset ]
,title : _('Status')
,autoHeight : true
};
Ext.apply(this, Ext.apply(this.initialConfig, config));
Ext.ux.form.StatusFieldSet.superclass.initComponent.call(this, arguments);
}
,showOnPending: function(v) {
if(v == 'pending'){
this.publishData_fieldset.show();
} else {
this.publishData_fieldset.hide();
}
}
});
Ext.reg('statusfieldset', Ext.ux.form.StatusFieldSet);
UPDATE:
I've managed to work it out by overloading the setValue method on the combobox instance. But it's by no means an elegant nor good solution if you ask me.
this.combo.setValue = function(v){
this.showOnPending(v);
return Ext.form.ComboBox.superclass.setValue.apply(this.combo, arguments);
}.createDelegate(this);
I would like to get some input from ExtJS veterans, how they would handle it.
Yep, setValue doesn't fire any events. I can only speculate as to why. I can tell you that You are stepping on any functionality that Combo adds to setValue with your work around though.
Something like this would be safer.
this.combo.setValue = this.combo.setValue.createSequence(this.showOnPending, this);
There is also some code out there that will 'fix' setValue so it fires an event. I'll try to find it. It adds a second parameter to setValue. You could override Combo.prototype.setValue using Ext.override with it: http://code.extjs.com:8080/ext/ticket/185.
In the end I think creating the sequence is still your safest bet.
Adding a change event to a combobox's setValue method is fairly easy using an override class:
Ext.define('<app_name>.override.form.field.ComboBox', {
override: 'Ext.form.field.ComboBox',
setValue(newValue) {
let oldValue = this.getValue();
this.callParent(arguments);
this.fireEvent('change', this, newValue, oldValue)
}
}
You'll just need to make sure that file containing this code gets loaded by the application. I'm still using Ext 5 so I add it to the requires array of the project's Application.js file, but I believe Ext 6 has an override folder and simply placing this file there ensures that it's loaded.

Resources