Trying to create an inline edit form.
I have a form that looks like this:
var editPic = "<img src='https://s3.amazonaws.com/bzimages/pencil.png' alt='edit' height='24' width='24' style='margin-left: 10px;'/>";
var submitPic = "<img id='submitPic' src='https://s3.amazonaws.com/bzimages/submitPic.png' alt='edit' height='24' width='24'/>";
Ext.define('BM.view.test.Edit', {
extend: 'Ext.form.Panel',
alias: 'widget.test-edit',
layout: 'anchor',
title: 'Edit Test',
defaultType: 'displayfield',
items: [
{name: 'id', hidden: true},
{
name: 'name',
fieldLabel: 'Name',
afterSubTpl: editPic,
cls: 'editable'
},
{
name: 'nameEdit',
fieldLabel: 'Name',
xtype: 'textfield',
hidden: true,
cls: 'editMode',
allowBlank: false,
afterSubTpl: submitPic
}
]
});
The controller looks like this (a lot of events):
init: function() {
this.control({
'test-edit > displayfield': {
afterrender: this.showEditable
},
'test-edit': {
afterrender: this.formRendered
},
'test-edit > field[cls=editMode]': {
specialkey: this.editField,
blur: this.outOfFocus
}
});
},
outOfFocus: function(field, event) {
console.log('Lost focus');
this.revertToDisplayField(field);
},
revertToDisplayField: function(field) {
field.previousNode().show();
field.hide();
},
formRendered: function(form) {
Ext.get('submitPic').on('click', function (event, object) {
var field = Ext.get(object).parent().parent().parent().parent();
var cmp = Ext.ComponentQuery.query('test-edit > field[cls=editMode]');
});
},
editField: function(field, e) {
var value = field.value;
if (e.getKey() === e.ENTER) {
if (!field.allowBlank && Ext.isEmpty(value)){
console.log('Not permitted!');
} else {
var record = Ext.ComponentQuery.query('test-edit')[0].getForm().getRecord();
Ext.Ajax.request({
url: '../webapp/tests/update',
method:'Post',
params: {
id: record.getId(),
fieldName: field.name,
fieldValue: field.value
},
store: record.store,
success: function(response, t){
field.previousNode().setValue(value);
t.store.reload();
var text = response.responseText;
// process server response here
console.log('Update successful!');
}
});
}
this.revertToDisplayField(field);
} else if (e.getKey() === e.ESC) {
console.log('gave up');
this.revertToDisplayField(field);
}
},
showEditable: function(df) {
df.getEl().on("click", handleClick, this, df);
function handleClick(e, t, df){
e.preventDefault();
var editable = df.nextNode();
editable.setValue(df.getValue());
editable.show();
editable.focus();
df.hide();
}
},
I'm using the 'afterSubTpl' config to add the edit icon, and the accept icon.
I have listeners set up to listen on click events concerning them, but after they are clicked, I only have the element created by Ext.get('submitPic'). Now I want to have access to the the Ext field and form that surround it. The parent method only brings back other DOM elements. How do I connect between them? You can see what I tried in formRendered.
I hope someone can clarify this little bit for me.
Walk up the DOM tree until you find a component for the element's id:
getCmpFromEl = function(el) {
var body = Ext.getBody();
var cmp;
do {
cmp = Ext.getCmp(el.id);
el = el.parentNode;
} while (!cmp && el !== body);
return cmp;
}
Ext.Component.from(el) does exactly this since ExtJS 6.5.0, as I just learnt. Doc
Source
You can get the component by id, but only if your component and its dom element have the same id (they usually do):
Ext.getCmp(yourelement.id)
But this is not exactly good practice -- it would be better to set up your listeners so that the handler methods already have a reference to the component. For example, in your 'submitPic' component, you could define the click listener like this:
var me = this;
me.on({
click: function(arguments){
var cmp = me;
...
});
Related
I have a grid with thousands of records. It works almost fine. When I programmatically call this method:
selectionModel.selectAll(true);
it works great. My script is not freezed, because of this true parameter, which according to docs suppresses any select events. However, when I select all records via a header checkbox (which selects and deselects all records), my script gets freezed. I guess, it is because by default select events are not suppressed. I tried to find a config, which globally supresses select events, but could not find it. So, my question is how can I fix this issue? How can I globally suppress select events in my grid selModel?
You can handle using overriding onHeaderClick method of grid CheckboxModel.
In this Fiddle, I have created a demo using same method onHeaderClick.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
var store = Ext.create('Ext.data.Store', {
fields: ['number'],
data: (() => {
let data = [];
for (let i = 1; i <= 50000; i++) {
data.push({
'number': i
})
}
return data;
})()
});
Ext.create('Ext.grid.Panel', {
title: 'Demo',
store: store,
itemId: 'demogrid',
columns: [{
text: 'Number',
flex: 1,
dataIndex: 'number'
}],
height: window.innerHeight,
renderTo: Ext.getBody(),
selModel: {
checkOnly: false,
mode: 'SIMPLE',
onHeaderClick: function (headerCt, header, e) {
var me = this,
store = me.store,
isChecked, records, i, len,
selections, selection;
if (me.showHeaderCheckbox !== false && header === me.column && me.mode !== 'SINGLE') {
e.stopEvent();
isChecked = header.el.hasCls(Ext.baseCSSPrefix + 'grid-hd-checker-on');
if (isChecked) {
console.time();
me.deselectAll(true);
console.timeEnd();
} else {
console.time();
me.selectAll(true);
console.timeEnd();
}
}
}
},
selType: 'checkboxmodel',
buttons: [{
text: 'Select All',
handler: function (btn) {
var grid = btn.up('#demogrid');
console.time();
grid.getSelectionModel().selectAll(true);
console.timeEnd();
}
}, {
text: 'Deselect All',
handler: function (btn) {
var grid = btn.up('#demogrid');
console.time()
grid.getSelectionModel().deselectAll(true);
console.timeEnd();
}
}]
});
}
});
use suspendEvents function on model to stop all events and after you done you can start all events by resumeEvents
grid.getSelectionModel().suspendEvents();
grid.getSelectionModel().resumeEvents();
I have a fiddle which demonstrates this strange behaviour. In a nutshell, I have a custom field which extends Ext.DataView. I need to extend dataview, because this field is supposed to have dynamic contents. This is how my field is defined:
Ext.define('Ext.ux.SimpleList', {
extend: 'Ext.DataView',
alias: 'widget.simplelist',
requires: [
'Ext.XTemplate'
],
itemSelector: 'div.record',
isFormField: true,
getFieldIdentifier: function () {
return this.name;
},
getModelData: function() {
var me = this;
var data = {};
data[me.getFieldIdentifier()] = me.getValue();
return data;
},
getSubmitData: function() { return {}; },
submitValue: true,
isValid: function () { return true; },
isDirty: function () { return true; },
validate: function () { return true; },
isFileUpload: function() { return false; },
constructor: function(config) {
Ext.applyIf(config, {
tpl: [
'{% var name = this.owner.name; %}',
'<tpl for=".">',
'<div class="record"><input record-id="{id}" type="checkbox" name="{[name]}" /> {label}</div>',
'</tpl>',
{compiled: true}
]
});
this.callParent([config]);
},
getValue: function () {
var cb = this.el.select("input").elements, i, res = [];
for (i in cb) {
if (cb.hasOwnProperty(i) && cb[i].checked) {
res.push(cb[i].getAttribute("record-id"));
}
}
return res;
},
setValue: function (values) {
//not yet implemented
}
});
And this is how I add this field to a form:
Ext.create("Ext.form.Panel",{
renderTo: Ext.getBody(),
items:[{
xtype: "textfield",
name: "text"
},{
xtype: "simplelist",
name: "list",
store: {
fields: ["id", "label", "checked"],
data: [{"id": "1", "label": "One"},{"id": "2", "label": "Two"}]
}
},{
xtype: "button",
text: "Submit",
handler: function () {
var frm = this.up("form").getForm();
console.log(frm.getFieldValues()); // it' ok
//simplelist field is not submitted
this.up("form").getForm().submit({
url: "/"
});
}
}]
});
As you can see, when I submit the form I log to the console form field values. And what is interesting about that, is that I see my custom field among those field values. So, I have a field with isFormField set to true, this field is in the list returned by form getFields() method and this field is also among those values returned by form getFieldValues() method, but still this field is not submitted. What is wrong with that and how can I fix it?
Your code uses basicForm.getFieldValues(), which calls basicForm.getValues() with some parameters, while the form while submitting uses the same method with different parameters. One of those parameters is useDataValues, which decides whether to use the getModelData or getSubmitData.
You are returning empty object in your getSubmitData method, which prevents it to correctly get the values.
All you need to change, for both methods to work in your current state, is this:
getSubmitData: function() {
return this.getModelData();
}
I have a regular tree with elements. What i want to do is following:
When I reload the page, the selected item must be the same as before ( I select only 1 item in the tree).
For example, when I click on 'Sue Potato' - it is selected and when I refresh the page, it must look the same (be also selected).
I've tried reading some Stateful, Provider, Manager on the Sencha Docs, but I didn't get it.
Controller code:
Ext.define('FirstApp.controller.Main', {
extend: 'Ext.app.Controller',
refs: [
{
ref: 'grid',
selector: 'lesson-grid'
},
{
ref: 'tree',
selector: 'school-tree'
}
],
init: function() {
Ext.state.Manager.setProvider(Ext.create('Ext.state.LocalStorageProvider'));
}
});
Tree code:
Ext.define('FirstApp.view.SchoolTree', {
extend: 'Ext.tree.Panel',
xtype: 'school-tree',
stateful: true,
stateId: 'stateGrid',
stateEvents:['selection'],
constructor: function() {
var that = this;
this.store = Ext.create('FirstApp.store.School');
this.store.on('load', function () {
that.getSelectionModel().select(1, true);
});
this.callParent(arguments);
this.getState = function() {
return that.getSelectionModel().getSelection();
};
this.applyState = function() {
};
}
});
Help would be much appreciated.
This is a working code of the requirement above.I had to get an id of the selected element and then pass it to applyState.
Ext.define('FirstApp.view.SchoolTree', {
extend: 'Ext.tree.Panel',
xtype: 'school-tree',
stateful: true,
stateId: 'stateTree',
stateEvents:['selectionchange'],
constructor: function() {
var that = this;
this.store = Ext.create('FirstApp.store.School');
this.store.on('load', function () {
that.getSelectionModel().select(1);
});
this.callParent(arguments);
},
getState: function() {
return {
'stateTree': this.getSelectionModel().getSelection()[0].getId()
};
},
applyState: function(state) {
var me = this;
this.store.on('load', function(record) {
record = this.getById(state.stateTree);
me.getSelectionModel().select(record);
});
}
});
You stored tree state and set it into State Manager
Ext.state.Manager.setProvider(Ext.create('Ext.state.LocalStorageProvider'));
So when you will refresh your page state will apply and an item will be also selected.
Is there any requirement to store state of tree? If yes and still you don't want to selected then you can forcefully clear selection on tree render.
I building a sortable table in Meteor with Reactive-Table and having trouble getting my delete button to work for removing entries from the table.
Please see my javascript code below:
Movies = new Meteor.Collection("movies");
if (Meteor.isClient) {
Template.body.events({
"submit .new-movie": function (event) {
var title = event.target.title.value;
var year = event.target.year.value;
var genre = event.target.genre.value;
Movies.insert({
title: title,
year: year,
genre: genre
});
event.target.title.value = "";
event.target.year.value = "";
event.target.genre.value = "0";
return false;
}
});
Template.moviestable.events({
"click .deletebtn": function (event) {
Movies.remove(this._id);
}
});
Template.moviestable.helpers({
movies : function () {
return Movies.find();
},
tableSettings : function () {
return {
showFilter: false,
fields: [
{ key: 'title', label: 'Movie Title' },
{ key: 'year', label: 'Release Year' },
{ key: 'genre', label: 'Genre' },
{ key: 'edit', label: 'Edit', fn: function () { return new Spacebars.SafeString('<button type="button" class="editbtn">Edit</button>') } },
{ key: 'delete', label: 'Delete', fn: function () { return new Spacebars.SafeString('<button type="button" class="deletebtn">Delete</button>') } }
]
}
}
});
}
Can anyone tell me what I'm doing wrong?
In the reactive tables docs, there's an example of how to delete rows from the table. Adapting the example in the docs for your needs, your event should look like this:
Template.moviestable.events({
'click .reactive-table tbody tr': function (event) {
event.preventDefault();
var objToDelete = this;
// checks if the actual clicked element has the class `deletebtn `
if (event.target.className == "deletebtn") {
Movies.remove(objToDelete._id)
}
}
});
The problem you are having is that you are trying to find the _id property on the button click instead of the row click.
If you do console.log(this) on your button click event (as you have it in your question above) you will get something like this Object {key: "delete", label: "", fieldId: "2", sortOrder: ReactiveVar, sortDirection: ReactiveVar} which does not contain the property _id
It is easier to register the row click, where the row object is the actual document you are trying to delete, and then check if the event's target has the delete class you added.
How to disable the delete button using if condition in Extjs for ex;i want to disable the button if it satifies the given if condition else remain enabled.
if(validAction(entityHash.get('entity.xyz'),actionHash.get('action.delete')))
This is the grid Delete button code.
Ext.reg("gridheaderbar-inActive", Ad.GridInActiveButton,{
xtype: 'tbspacer', width: 5
});
Ad.GridCampDeleteButton = Ext.extend(Ext.Toolbar.Button, {
//text: 'Delete',
cls: 'ad-img-button',
width:61,
height:40,
iconCls: 'ad-btn-icon',
icon: '/webapp/resources/images/btn_del.png',
handler:function(){
statusChange(this.parentBar.parentGrid, 'Delete')
}
});
create actioncolumn and make custom renderer:
{
xtype: 'actioncolumn',
width: 38,
renderer: function (val, metadata, record) {
this.items[0].icon = '${CONTEXT_PATH}/images/' + record.get('fileType') + '.png';
this.items[0].disabled = !record.get('isDownloadActionEnable');
this.items[1].disabled = !record.get('isDeleteActionEnable');
metadata.style = 'cursor: pointer;';
return val;
},
items: [
{
icon: '${CONTEXT_PATH}/images/pdf.png', // Use a URL in the icon config
tooltip: 'Download',
handler: function (grid, rowIndex, colIndex) {
//handle
}
},
{
icon: '${CONTEXT_PATH}/images/delete.png', // Use a URL in the icon config
tooltip: 'Delete',
handler: function (grid, rowIndex, colIndex) {
handle
}
}
]
}
in this example You see additionally how to change dynamically icon.
One way to solve it is to attach a unique ID to your delete button and bind a listener to the selectionchange event of your SelectionModel, whenever the selection changes you can check whatever you want and enable/disable the button as you see fit.
ie.
Ad.GridCampDeleteButton = Ext.extend(Ext.Toolbar.Button, {
id: 'btnDelete',
cls: 'ad-img-button',
...
});
and in your selectionmodel do something like this :
var sm = new Ext.grid.CheckboxSelectionModel({
...
,listeners: {
'selectionchange' : {
fn: function(sm) {
if (sm.hasSelection()) {
var selected = sm.getSelected();
if (selected.get('field') == value) {
Ext.getCmp('btnDelete').disable();
}
else {
Ext.getCmp('btnDelete').enable();
}
}
}
,scope: this
}
}
});