ExtJS - disable/enable elements on combo change - javascript

The title says much about it. I will pass you an example below:
let scalesField = {
xtype: 'combo',
name: property.name + 'scale',
listeners: {
change: function (combo, selectedValue) {
// here would be some logic
// Tried with:
Ext.Array.each(possibleValues, function (single, index) {
possibleValues[index].disabled = true;
if (possibleValues[index].scale_id === selectedValue) {
possibleValues[index].disabled = false;
}
});
}
}
};
if (possible_values.length > 0) {
Ext.Array.each(possible_values, function (single, index) {
fields.push({
xtype: 'checkboxfield',
fieldLabel: possible_values[index].name,
name: possible_values[index].name,
labelWidth: 100,
});
});
}
Variable 'possible_values' contain all possible checkboxes as are defined in the 'if' block. I want to disable or enable checkboxes depending on what option user choose in combo(select option dropdown).
After running code as below I can see in the console that property disabled is changed but it does not apply to a view.
How to solve this in ExtJS?

You can use it like below:-
Ext.ComponentQuery.query('checkboxfield[name=' + possibleValues[index].name + ']')[0].setDisabled(true /*/false*/ );

Related

ExtJS 7.1 Tag field is executing XSS tag

I am having an issue regarding the tagfield component when entering <img src=a onerror=alert('xss!')>. This tag is being executed after entering the whole value. I've tried preventing the tag execution on keyup, keypress, keydown, and beforequery events and it still executing. This block of code prevent the event from executing when it detects an XSS tag.
Ext.application({
name: 'Fiddle',
launch: function () {
var shows = Ext.create('Ext.data.Store', {
fields: ['id', 'show'],
data: []
});
Ext.create('Ext.form.Panel', {
renderTo: Ext.getBody(),
title: 'Sci-Fi Television',
height: 200,
width: 500,
items: [{
xtype: 'tagfield',
itemId: 'tagField',
fieldLabel: 'Select a Show',
store: shows,
displayField: 'show',
valueField: 'id',
queryMode: 'local',
filterPickList: false,
listeners: {
beforequery: function () {
var editor = Ext.ComponentQuery.query('#tagField')[0];
if (editor.inputEl.getValue().search(new RegExp('(<([^>]+)>)')) >= 0) {
editor.inputEl.dom.value = '';
return false;
}
},
keypress: function (textfield, event) {
var editor = Ext.ComponentQuery.query('#tagField')[0];
if (editor.inputEl.getValue().search(new RegExp('(<([^>]+)>)')) >= 0) {
editor.inputEl.dom.value = '';
return false;
}
},
keydown: function (textfield, event) {
var editor = Ext.ComponentQuery.query('#tagField')[0];
if (editor.inputEl.getValue().search(new RegExp('(<([^>]+)>)')) >= 0) {
editor.inputEl.dom.value = '';
return false;
}
},
}
}]
});
}
});
enter image description here
This took a little while to hunt down, but apparently in Ext.form.field.ComboBox, there's an onFieldMutation handler that really is the key to all of this. Take a look at this Fiddle and the code that takes care of handling this... I believe this is what you're looking for:
Ext.define('ComboOverride', {
override: 'Ext.form.field.ComboBox',
onFieldMutation: function (e) {
var inputDom = this.inputEl.dom;
if (Ext.String.hasHtmlCharacters(inputDom.value)) {
inputDom.value = '';
alert('XSS Detected, Removing');
}
return this.callParent(arguments);
}
});

angular-slickgrid, trigger the cell edit on select editor change event

I am using angular-silkgrid with angular 7. I am using inline editing feature. I am using single select editor for inline edit. Currently I want to achieve this functionality:
As soon as user click on the editable field , the select drop down will be visible.On select any option from select dropdown the inline mode should exist and column value should be updated.
currently I need to click on other field to exit from inline mode(I want to achieve this on select option select)
editor: {
// display checkmark icon when True
enableRenderHtml: true,
// tslint:disable-next-line:max-line-length
collection: [{
value: 1,
label: 'Sucessful'
}, {
value: 2,
label: 'Unsucessful'
}],
model: Editors.singleSelect, // CustomSelectEditor
elementOptions: {
autoAdjustDropPosition: false,
onClick: (event, rr) => {
// here i want to write some code which can trigger to grid to start update
}
}
}
Thanks All for the answers. I have solved my issue as below:
editor: {
enableRenderHtml: true,
collection: [{ value: CCLStaus.Sucessfull, label: 'Sucessful' }, { value: CCLStaus.UnSucessfull, label: 'Unsucessful' }],
model: Editors.singleSelect,// CustomSelectEditor
elementOptions: {
onClick: (event) => {
const updateItem = this.angularSilkGrid.gridService.getDataItemByRowIndex(this.rowInEditMode);
updateItem.status = +event.value;
this.angularSilkGrid.gridService.updateItem(updateItem, { highlightRow: false });
this.angularSilkGrid.gridService.renderGrid();
}
}
}
Generally,
grid.getEditorLock().commitCurrentEdit()
will commit and close the editor.
Also, any of
grid.navigateRight()
grid.navigateLeft()
grid.navigateDown()
grid.navigateUp()
grid.navigateNext()
grid.navigatePrev()
will commit and exit gracefully. In the select2 editor, you'll notice:
this.init = function () {
...
// Set focus back to select2 element on closing.
$input.on('select2:close', function (e) {
if ((e.params.originalSelect2Event && e.params.originalSelect2Event.data)
|| e.params.key === 9) {
// item was selected with ENTER or no selection with TAB
args.grid.navigateNext();
} else {
// closed with no selection
setTimeout(function () {
$input.select2('focus');
}, 100);
}
});
};
this.destroy = function () {
$input.select2('destroy');
$input.remove();
};
, noting that args.grid.navigateNext() will commit and close the editor, including calling the destroy() method at the appropriate time.
From the Angular-Slickgrid Editor Example there's a checkbox in the example to auto commit and that is a setting to you need to enable in your Grid Options
this.gridOptions = {
autoEdit: true,
autoCommitEdit: true,
}
The lib will internally call grid.getEditorLock().commitCurrentEdit() like Ben wrote in his answer, in Angular-Slickgrid you can just set the autoCommitEdit flag that I added.

ExtJs form multiple button for different binding

Need to bind my form elements separately for different buttons. Using allowBlank in elements for sending binding conditions and formBind in buttons for binding the buttons. Need to do this like in this simplest way. (ExtJs 4.2.1 Classic)
Example
Ext.create('Ext.form.Panel', {
......
items: [
Ext.create('Ext.form.field.Date', {
.....,
allowBlank: false, //bind for both search & download button.
.....
}),
......, //// All rest elements bind for both search & download button.
Ext.create('Ext.form.ComboBox', {
......,
allowBlank: false, //bind for only download button.
......
})
],
buttons: [
{
text: 'Search',
formBind: true, /// Need to bind for specific field only.
},
{
text: 'Download',
formBind: true, /// Need to bind for all.
},
............
});
If any other data or details is necessary then please don't hesitate to ask.
I created a fiddle here that I think should accomplish what you're trying to do. The idea to use an event listener on the combobox, instead of the formBind config of the Download button:
https://fiddle.sencha.com/#view/editor&fiddle/289a
Ext.create('Ext.form.Panel', {
renderTo: Ext.getBody(),
itemId: 'exampleForm',
items: [Ext.create('Ext.form.field.Date', {
allowBlank: false, //bind for both search & download button.
}),
Ext.create('Ext.form.ComboBox', {
allowBlank: false, //bind for only download button.
listeners: {
change: function (thisCombo, newValue, oldValue, eOpts) {
if (Ext.isEmpty(newValue)) {
thisCombo.up('#exampleForm').down('#btnDownload').setDisabled(true);
} else {
thisCombo.up('#exampleForm').down('#btnDownload').setDisabled(false);
}
}
},
store: ['item1', 'item2']
})
],
buttons: [{
text: 'Search',
formBind: true, /// Need to bind for specific field only.
}, {
itemId: 'btnDownload',
text: 'Download',
disabled: true
//formBind: true, /// Need to bind for all.
}]
});
There is no standard quick way to do this, you might want to write a plugin for this. I've put together one:
Ext.define('App.plugin.MultiDisableBind', {
extend: 'Ext.AbstractPlugin',
alias: 'plugin.multidisablebind',
/**
* #cfg
* Reference to the fields that this button depends on.
* Can contain either direct references, or a query selectors that will be
* executed with the button as the root
*/
depFields: null,
/**
* #property
* A map object with field ids as key, and field values as value
*/
valuesMap: null,
init: function (cmp) {
this.setCmp(cmp);
cmp.on('render', this.setup, this);
},
setup: function () {
var cmp = this.getCmp(),
depFields = this.depFields,
valuesMap = {};
if (!Ext.isArray(depFields)) {
depFields = [depFields];
}
Ext.Array.forEach(depFields, function (field) {
if (Ext.isString(field)) {
field = cmp.query(field)[0];
}
cmp.mon(
field,
'change',
Ext.Function.createThrottled(this.updateValuesMap, 300, this),
this
);
valuesMap[field.getId()] = field.getValue();
}, this);
this.valuesMap = valuesMap;
this.updateCmpDisabled();
},
updateValuesMap: function (depField, newValue) {
this.valuesMap[depField.getId()] = newValue;
this.updateCmpDisabled();
},
updateCmpDisabled: function () {
var cmp = this.getCmp(),
toDisable = true;
Ext.Object.each(this.valuesMap, function (fieldId, fieldValue) {
if (!Ext.isEmpty(fieldValue)) {
toDisable = false;
return false
}
});
cmp.setDisabled(toDisable);
}
});
You can use this plugin in your buttons like so:
xtype: 'button',
text: 'My button',
plugins: {
ptype: 'multidisablebind',
depFields: ['^form #fieldQuery', fieldVar]
}
In the depFields config you specify references to the fields that button's disabled state depends on, and the plugin will monitor these fields, so that on each field value change it will update the disabled state.
Here is a working fiddle: https://fiddle.sencha.com/#view/editor&fiddle/28cm
I have created a fiddle for you. The code uses bind and formBind respectively for the two different buttons. May be you want something like this.

How to apply show less and show more on cells of a reactive table in meteor

document_table_Settings : function ()
{
return{
rowsPerPage: 5,
showNavigation: 'auto',
showColumnToggles: false,
fields: [
{key: 'para',label: 'Para',sortable: false},
{key: 'desc', label: 'Description',sortable: false},
{
key: 'rowId', label: 'Delete',sortable: false, fn: function (rowId, object) {
var html = "<button name='Del' id=" + rowId + " class='btn btn-danger'>Delete</button>"
return new Spacebars.SafeString(html);
}
},
{
key: 'rowId', label: 'Edit',sortable: false, fn: function (rowId, object) {
var html = "<button name='edit' id=" + rowId + " class='btn btn-warning'>Edit</button>"
return new Spacebars.SafeString(html);
}
}
]
};
}
I want to show description entries having show more and show less feature .As the description is long enough. so after 100 character it shows button to toggle.
If I understand you correctly, you are trying to only show the first 100 characters of the 'Description' column in the Reactive Table and then add some mechanism so that the user can click or rollover to see the entire 'Description' text.
There are a few ways to achieve this and I have provided two options below (in order of simplicity).
For a low tech rollover option, truncate the text to only show the first 100 characters, add an ellipsis (...) to the end of your text, then use the title property in a span element to show the full text on rollover.
First you will need to define a 'truncate' Template helper (I would make this a global helper so that you can use anywhere in your app).
Template.registerHelper('truncate', function(strValue, length) {
var len = DEFAULT_TRUNCATE_LENGTH;
var truncatedString = strValue;
if (length && length instanceof Number) {
len = length;
}
if (strValue.length > len) {
truncatedString = strValue.substr(1, len) + "...";
}
return truncatedString;
});
Then create a new Template for the column.
<template name="field_description">
<span title="{{data.description}}">{{truncate data.description}}</span>
</template>
And finally, change your Reactive Table configuration to use a Template.
fields: [
...,
{ key: 'desc', label: 'Description', tmpl: Template.field_description }
...,
];
For a slightly more complicated option, you can take a similar approach but add a clickable link that would show more or less detail. To get it to work you have to define a few Reactive Vars, define an event handler, and change your 'Description' Template accordingly. Here is a rough solution that should work.
Change your template like so.
<template name="field_description">
<span>{{truncatedDescription}}
{{#if showLink}}
{{linkState}}
{{/if}}
</span>
</template>
Then add the necessary logic to your field_description template (including an event handler).
import { Template } from 'meteor/templating';
import './field-description.html';
Template.field_descirption.onCreated(function() {
const MAX_LENGTH = 100;
this.description = new ReactiveVar(Template.currentData().description);
this.showMore = new ReactiveVar(true);
if (this.description.get().length > MAX_LENGTH) {
this.description.set(Template.currentData().description.substr(1, MAX_LENGTH));
}
this.showLink = () => {
return Template.currentData().description.length > MAX_LENGTH;
};
this.toggleTruncate = () => {
if (this.showMore.get()) {
this.description.set(Template.currentData().description);
this.showMore.set(false);
} else {
this.description.set(Template.currentData().description.substr(1, MAX_LENGTH));
this.showMore.set(true);
}
};
});
Template.field_descirption.helpers({
truncatedDescription: function() {
return Template.instance().description.get();
},
showLink: function() {
return Template.instance().showLink();
},
linkState: function() {
if (Template.instance().showMore.get()) {
return 'show more';
} else {
return 'show less';
}
};
});
Template.field_descirption.events({
'click .js-more-less'(event, instance) {
instance.toggleTruncate();
},
});
Lastly, make sure your Reactive Table config is still setup to use a Template for the field.
fields: [
...,
{ key: 'desc', label: 'Description', tmpl: Template.field_description }
...,
];
Note that the second option makes use of Meteor's Reactivity to solve the problem. Let me know if you need additional explanation on how the 2nd solution works.
That should do it!

Dynamically created check box doesn't get checked on button click in ExtJS

I create a check box dynamically (based on condition) on "create checkbox" button and added this checkbox in panel.
According to my condition, Only 1 checkbox will be added in panel and it's item id will be "a1".
When click on another button "checkedcheckbox" checkbox should be checked but it doesn't. When i get this checkbox by itemid on button click, then it show undefined in developer tools. If i get it by panel items then it doesn't show undefine but checkbox doesn't checked.
PROBLEM
Why checkbox show undefined if i get it by itemId ?
Why Checkbox is not checked if i am getting by panel items. It should be get in both ways by getting directly through itemid and panel items.
There is some problem on my account in sencha fiddler, that's why i can create a fiddler for you.
Code
Ext.onReady(function () {
var window = new Ext.Window({
id: 'grdWindow',
width: 400,
height: 500,
title: 'Grid Samples',
items: [
{
xtype: 'button',
text: 'Create checkbox',
handler: function () {
var obj1 = [
{ a: 1},
{ a: 2},
{ a: 3},
{ a: 4}
];
var obj2 = [
{ a: 1 },
{ a: 5 }
];
var i = 1;
var panel = Ext.getCmp('pnlTesting');
Ext.each(obj1, function (ob1) {
Ext.each(obj2, function (ob2) {
if (ob1.a == ob2.a) {
panel.add({
items:[
{
xtype: 'checkbox',
itemId: 'a'+i
}
]
});
return false;
}
});
});
}
},
{
xtype: 'panel',
id: 'pnlTesting',
height: 100,
renderTo: Ext.getBody()
},
{
xtype: 'button',
text: 'checkedcheckbox',
handler: function () {
Ext.getCmp('pnlTesting').items.items[0].items.items[0].checked = true;
//Ext.getCmp("a1").checked = true;
//Ext.getCmp('pnlTesting').doLayout();
}
}
]
}).show();
});
I would recommend learning the usage of .up() .down() .prev(), .next() and .query()
They are powerful tools to navigate through every component in your object structure without dealing with special item ids. You can also fetch components via config options like component.query('button[name="mybutton"]')
I made a (very) small example for your requirement in sencha fiddle: https://fiddle.sencha.com/#fiddle/sii
The problem is that if you want to change the state of the checkbox you should do it with setValue(true) and not checked=true.
{
xtype: 'button',
text: 'checkedcheckbox',
handler: function (btn) {
Ext.getCmp('pnlTesting').items.items[0].items.items[0].setValue(true);
}
}
And also, that's an ugly way of getting the component, i get it with down() and its itemId
Ext.getCmp('pnlTesting').down('#a1').setValue(true);
P.D: You should improve this selector because using id and getCmp() is not a good practice for ExtJS.

Categories