I am trying to display my JSON in a propertygrid where I have nested level of JSON structure. As per to the property grid documentation the only types supported are boolean, string, date, number. So am only able to see the flatten level information and not the nested object.
Wanted to know if there is any configuration in propertygrid which will allow me to display and edit the nested information ? or any other component available which will be helpful instead of propertygrid
Below is the sample config and fiddle:
Ext.create('Ext.grid.property.Grid', {
title: 'Properties Grid',
width: 300,
renderTo: Ext.getBody(),
source: {
"allowBlank": "My Object",
"minValue": 1,
"maxValue": 10,
"itemDetails": {
"name": "name 1",
"type": "Object"
},
"Description": "A test object"
},
sourceConfig: {
allowBlank: {
displayName: 'Required'
}
}
});
You can use editable column tree:
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [{
text: "allowBlank",
value: "My Object",
leaf: true
}, {
text: "minValue",
value: "1",
leaf: true
}, {
text: "maxValue",
value: 10,
leaf: true
}, {
text: "itemDetails",
value: "",
expanded: true,
children: [{
text: "name",
value: "name 1",
leaf: true
}, {
text: "type",
value: "Object",
leaf: true
}]
}, {
text: "Description",
value: "A test object",
leaf: true
}]
}
});
Ext.create('Ext.tree.Panel', {
title: 'Simple Tree',
height: 200,
store: store,
rootVisible: false,
plugins: {
cellediting: {
clicksToEdit: 2,
listeners: {
beforeedit: function (editor, context, eOpts) {
if (!context.record.isLeaf()) {
return false;
}
var column = context.column;
switch (typeof context.record.get('value')) {
case "string":
column.setEditor({
xtype: 'textfield'
});
return;
case "number":
column.setEditor({
xtype: 'numberfield'
});
return;
//...
//...
default:
column.setEditor({
xtype: 'textfield'
});
return;
}
},
}
}
},
columns: [{
xtype: 'treecolumn',
text: 'Headers',
dataIndex: 'text'
}, {
text: 'Value',
dataIndex: 'value',
editor: {
xtype: 'textfield'
}
}],
renderTo: Ext.getBody()
});
Related
I want to have REST operations on child object of a parent object on Ext Grid. I need to use rowExpander not rowWidget since I am using modern toolkit.
Here is my sample JSON data from my API:
{
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"hasPreviousPage": false,
"hasNextPage": false
},
"data": [
{
"id": 2,
"customer": "Mark",
"dateRented": "2021-02-09T21:18:40.667",
"movieRentals": [
{
"id": 5,
"rentalDetailDtoId": 2,
"movie": "Shingeki no Kyojin",
"dateReturned": null
},
{
"id": 6,
"rentalDetailDtoId": 2,
"movie": "Insidous 2",
"dateReturned": null
}
]
},
{
"id": 1,
"customer": "Samuel",
"dateRented": "2021-02-09T21:17:18.403",
"movieRentals": [
{
"id": 3,
"rentalDetailDtoId": 1,
"movie": "Home Alone",
"dateReturned": null
},
{
"id": 4,
"rentalDetailDtoId": 1,
"movie": "Neighbors",
"dateReturned": null
}
]
}
]
}
I would like to display it per Customer and I have a REST action of POST on the movieRentals object. I would like to use RowExpander but I am not sure how to make it work.
Here is my current ExtJS Grid code:
Ext.define('Vidly.view.rental.DisplayRentalsView', {
extend: 'Ext.grid.Grid',
xtype: 'displayrentalsview',
reference: 'rentallist',
title: 'Rental List',
controller: 'displayrentalsviewcontroller',
viewModel: 'rentalsviewmodel',
reference:'displayrentalsviewgrid',
selType: 'rowmodel',
selModel:
{
mode: 'SINGLE'
},
viewConfig:
{
stripeRows: true
},
listeners: {
selectionchange: 'onSelectionChange',
show: 'onShow',
},
bind: {
store: '{RentalListStore}'
},
itemConfig: {
viewModel: true
},
plugins: {
pagingtoolbar: true
},
items: [
{
xtype: 'container',
docked: 'top',
items: [
{
docked: 'left',
xtype: 'button',
ui: 'decline',
itemId: 'returnRental',
text: 'Return Rental',
reference: 'btnReturnRental',
handler: 'onReturnClick',
disabled: true,
}
]
},
],
columns: [
{
text: "Customer",
flex: 1,
dataIndex: 'customer',
editor:
{
allowBlank: false
},
},
{
text: "Movie",
flex: 1,
dataIndex: 'movieRental',
editor:
{
allowBlank: false
},
},
{
text: "Date Rented",
flex: 1,
dataIndex: 'dateRented',
editor:
{
allowBlank: false
},
renderer: function (value, metaData, record) {
if (value != null && value != "") {
var dateRented = new Date(Date.parse(value))
return Ext.Date.format(dateRented, 'm/d/Y')
}
else {
return "";
}
}
},
{
text: "Date Returned",
flex: 1,
dataIndex: 'dateReturned',
editor:
{
allowBlank: false
},
renderer: function (value, metaData, record) {
if (value != null && value != "") {
var dateRented = new Date(Date.parse(value))
return Ext.Date.format(dateRented, 'm/d/Y')
}
else {
return "";
}
}
}
],
});
Its always good to provide an fiddle when your asking something in ExtJs
I Provided a fiddle here, I hope this helps you along
https://fiddle.sencha.com/#view/editor&fiddle/3bpk
Ext.application({
name: 'Fiddle',
launch: function () {
const store = Ext.create('Ext.data.Store', {
data: [{
"id": 2,
"customer": "Mark",
"dateRented": "2021-02-09T21:18:40.667",
"movieRentals": [{
"id": 5,
"rentalDetailDtoId": 2,
"movie": "Shingeki no Kyojin",
"dateReturned": null
}, {
"id": 6,
"rentalDetailDtoId": 2,
"movie": "Insidous 2",
"dateReturned": null
}]
}, {
"id": 1,
"customer": "Samuel",
"dateRented": "2021-02-09T21:17:18.403",
"movieRentals": [{
"id": 3,
"rentalDetailDtoId": 1,
"movie": "Home Alone",
"dateReturned": null
}, {
"id": 4,
"rentalDetailDtoId": 1,
"movie": "Neighbors",
"dateReturned": null
}]
}]
});
Ext.create('Ext.grid.Grid', {
store: store,
plugins: {
rowexpander: true
},
height: 500,
width: '100%',
itemConfig: {
body: {
tpl: '<ul>' +
'<tpl foreach="movieRentals">' +
'<li>Movie: {movie}</li>' +
'</tpl>' +
'</ul>'
}
},
columns: [{
text: 'Name',
dataIndex: 'customer',
width: 200
}, {
text: 'dateRented',
dataIndex: 'dateRented',
width: 250
}],
layout: 'fit',
fullscreen: true
});
}
});
and by the way, move those renderers into your viewController. Duplicate code is always ugly :-)
Ok, you should take a deeper look at the https://docs.sencha.com/extjs/7.3.1/modern/Ext.grid.Row.html#events
itemConfig: {
body: {
tpl: '<p>Hello World</p>',
listeners: {
beforeshow: sender => {
console.log(sender);
// Here you can tell your record to fetch data
}
}
}
}
feel free to play arround with the fiddle
https://fiddle.sencha.com/#fiddle/3bq5&view/editor
I have treepanel. I want to fire an event on click of only child element.
In my itemclick event it is firing all the time when I click. I want only to fire only when the last child is clicked.
Eg.: It should fire "Manage Application Child" not on the "Manage Application"
var root = {
expanded: true,
children: [{
text: "Configure Application",
expanded: true,
children: [{
text: "Manage Application",
children: [{
text: "Manage Application Child",
leaf: true
}]
}, {
text: "Scenario",
leaf: true
}]
}, {
text: "User Configuration",
expanded: true,
children: []
}, {
text: "Test Configuration",
//leaf: true,
expanded: true,
children: [{
text: "Manage User",
leaf: true
}, {
text: "User rights",
leaf: true
}]
}]
};
{
xtype: 'treepanel',
useArrows: true,
autoScroll: false,
animate: true,
enableDD: false,
title: 'Configuration',
width: 200,
height: 400,
rootVisible: false,
store: Ext.create('Ext.data.TreeStore', {
root: root
}),
listeners: {
itemclick: function (s, r) {
alert(r.data.text);
}
}
}
If i understand correctly, you just have to check if the node is "leaf":
itemclick: function (s, r) {
if (r.data.leaf){ //or r.data.children == null
alert(r.data.text);
}
}
I created FIDDLE i think it will help you what you want
I want to search for specific node in an ExtJs tree. The current code that I have allows node to be searched only at the first level. Please check this fiddle
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [{
text: "Javascript",
leaf: true
}, {
text: "ASP.net",
leaf: true
}, {
text: "Also ASP.net",
leaf: false,
children: [{
text: '1.1 foo',
leaf: false,
children: [{
text: "1.1.1 asp.net mvc",
expanded: true
}, {
text: "1.1.2 java",
expanded: true
}, {
text: "1.1.3 extjs",
expanded: true
}]
}, {
text: '1.2 bar',
leaf: true
}]
}, {
text: "ASP.net future",
leaf: true
}]
}
});
Ext.create('Ext.tree.Panel', {
title: 'Example Tree',
width: 200,
height: 450,
store: store,
rootVisible: false,
multiSelect: true,
renderTo: Ext.getBody(),
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
items: [{
text: 'Search for ASP.net',
handler: function () {
var me = this,
panel = me.up('panel'),
rn = panel.getRootNode(),
regex = new RegExp("ASP.net");
rn.findChildBy(function (child) {
var text = child.data.text;
if (regex.test(text) === true) {
console.warn("selecting child", child);
panel.getSelectionModel().select(child, true);
}
});
}
}]
}]
});
What I want:
Ability to search across all the levels in the tree
once a node is found, I want to expand it.
How can I achieve this?
Thank you
You can use this :
var c = rn.findChild("text","Also ASP.net",true);
c.expand();
true indicates a deep search.Please have a look at findChild.
Please check out the fiddle
This is what I was looking for : http://jsfiddle.net/tdaXs/17/
Thank you Devendra for suggesting Deep Search option.
var store = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true,
children: [{
text: "Javascript",
leaf: true
}, {
text: "ASP.net",
leaf: true
}, {
text: "Also ASP.net",
leaf: false,
children: [{
text: '1.1 foo',
leaf: false,
children: [{
text: "1.1.1 ASP.net mvc",
leaf: true,
expanded: true
}, {
text: "1.1.2 java",
leaf: true,
expanded: true
}, {
text: "1.1.3 extjs",
leaf: true,
expanded: true
}]
}, {
text: '1.2 bar',
leaf: true
}]
}]
}
});
Ext.create('Ext.tree.Panel', {
title: 'Example Tree',
width: 200,
height: 450,
store: store,
rootVisible: false,
multiSelect: true,
renderTo: Ext.getBody(),
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
items: [{
text: 'Search for ASP.net',
handler: function () {
var me = this,
panel = me.up('panel'),
rn = panel.getRootNode(),
regex = new RegExp("ASP.net");
//var c = rn.findChild("text", " asp.net", true);
rn.findChildBy(function (child) {
var text = child.data.text;
if (regex.test(text) === true) {
console.warn("selecting child", child);
panel.getSelectionModel().select(child, true);
}
});
}
}]
}]
});
I would like to implement a tree panel with content loaded dynamically from the server (as Json) and with a custom data model. But I dont know how to define a model and a data store for that tree. Can you provide some examples? If possible, I'd like to conform to the sencha mvc recommendations (the model and the data store defined as separate classes).
I knew how to do it in extjs 3 but i'm lost in version 4.
Best regards
RG
I experimented with a new MVC approach recently, and I managed to get it work with the treepanel. Nothing special actually:
View:
Ext.define('RoleBuilder.view.RoleList', {
extend: 'Ext.tree.Panel',
alias: 'widget.roles',
title: 'Roles',
store: 'Roles'
});
Store:
Ext.define('RoleBuilder.store.Roles', {
extend: 'Ext.data.TreeStore',
model: 'RoleBuilder.model.Role',
requires: 'RoleBuilder.model.Role',
root: {
text: 'Roles',
expanded: true
},
proxy: {
type: 'ajax',
url: loadRolesUrl,
actionMethods: 'POST',
reader: {
type: 'json'
}
}
});
Model:
Ext.define('RoleBuilder.model.Role', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int', mapping: 'Id' },
{ name: 'text', type: 'string', mapping: 'Text' },
{ name: 'leaf', type: 'boolean', mapping: 'Leaf' },
{ name: 'loaded', type: 'boolean', mapping: 'Loaded', defaultValue: false },
{ name: 'Properties'},
{ name: 'expanded', defaultValue: true }
]
});
Controller:
Ext.define('RoleBuilder.controller.RoleList', {
extend: 'Ext.app.Controller',
init: function () {
this.control({
'roles': {
itemcontextmenu: this.onItemContextMenuClick,
itemclick: this.onItemClick
}
});
this.application.on({
'role-saved': Ext.Function.bind(this.onRoleSaved, this)
});
},
..... too long, but you got the idea.
Hope it will help.
I struggle so much to get this working. I want to share with you in case you need it.
Here is my view:
Ext.define("GiipIq.view.Problem", {
extend: "Ext.window.Window",
alias: "widget.problemwindow",
titleAlign: "center",
closable: false,
layout: "border",
autoShow: true,
maximizable: true,
draggable: false,
resizable: false,
x: 0,
y: 0,
width: Ext.getBody().getViewSize().width/2,
height: Ext.getBody().getViewSize().height/2,
id: "problem-window",
getEastPanel: function() {
return {
region: "west",
xtype: "treepanel",
title: "Problems",
width: 200,
split: true,
collapsible: false,
floatable: false,
rootVisible: false,
useArrows: true,
store: Ext.create("GiipIq.store.Problems"),
id: "problems",
dockedItems: [{
xtype: "toolbar",
dock: "bottom",
layout: "fit",
items: [{
xtype: "button",
text: 'Click to Run Selected Problems',
id: "run-problems-button"
}]
}],
listeners: {
checkchange: function(node, checkedStatus, options) {
console.log("vp");
}
}
};
},
getCentralPanel: function() {
return {
xtype: "tabpanel",
width: (Ext.getBody().getViewSize()/2) - 200,
bodyBorder: false,
items: [{
title: "Problem Description",
id: "problem-description-tab"
},{
xtype: "panel",
title: "Source Code",
},{
xtype: "panel",
title: "Big O Analysis",
}]
};
},
initComponent: function () {
this.items = [
this.getEastPanel(),
this.getCentralPanel()
];
this.callParent(arguments);
}
});
Here is my store:
Ext.define("GiipIq.store.Problems", {
extend: "Ext.data.TreeStore",
storeId:"problems-store",
model: "GiipIq.model.Problem",
});
Here is my model:
Ext.define("GiipIq.model.Problem", {
extend: "Ext.data.Model",
fields: [
{ name: "text", type: "string" },
{ name: "leaf", type: "bool" },
{ name: "expanded", type: "bool" },
{ name: "checked", type: "bool" }
],
proxy: {
type: "ajax",
actionMethods: { read: "GET" },
api: { read: "app/problems.json", },
reader: {
type: "json",
root: "children"
},
listeners: {
exception: function(proxy, response, operation, opts) {
if(typeof(operation.error) == "string") {
Ext.Msg.alert("Error", "Connection to server interrupted" + operation.error);
}
}
}
}
});
Here is my json:
{
success: true,
children: [{
text: "algorithms", expanded: true, leaf: false, checked: false, children: [
{ text: "bit manipulation", leaf: true, checked: true },
{ text: "brain teaser", leaf: true, checked: true }
]
},{
text: "data structures", expanded: true, checked: false, leaf: false, children: [
{ text: "array and strings", leaf: true, checked: true },
{ text: "linked lists", leaf: true, checked: false}
]
},{
text: "knowledge based", expanded: true, leaf: false, checked: false, children: [
{ text: "C and C++", leaf: true, checked: false},
{ text: "Java", leaf: true, checked: false}
]
}]
}
(i posted this on the extjs forum too but recon SO is probably busier)
HI
I'm passing down the following json to a direct store:
{
"type": "rpc",
"tid": 2,
"action": "DirectReportDesigner",
"method": "GetReports",
"result": {
"total": 1,
"data": [{
"id": 1,
"FullTypeName": null,
"title": "test",
"useGroupedColConfig": false,
"groupTextTemplate": "{'ProviderName': ' Contract Number -- {gvalue}','ProviderName': ' Provider Name -- {gvalue}'}",
"groupHeaders": null,
"groupFields": "['CostElement2', 'CostElement3', 'CostElement4']",
"groupedHeaders": false,
"jsonUrl": "report/BudgetManagerBudgetData.rails",
"menuType": "rptmid",
"actualType": "rptmid",
"ignoreCols": "1",
"getRowClass": "settings.utils.highlightRowWhenCellEmptyClass",
"deleted": false,
"fitToScreen": false,
"isCopyOf": 0
}]
}
}
here is what the js code looks like:
Ext.extend(Ideal.ReportDesigner.ReportGrid, Ideal.UI.BaseGrid, {
pageSize: 25,
afterRender: function() {
this.getStore().load({
params: {
start: 0,
limit: 25
}
});
Ideal.ReportDesigner.ReportGrid.superclass.afterRender.apply(this, arguments);
},
header: false,
view: new Ext.grid.GridView({
autoFill: true
}),
cm: new Ideal.UI.ColumnModel([{
header: 'Report Name',
id: 'nameCol',
sortable: true,
dataIndex: 'title'
}, {
header: 'Json URL',
sortable: true,
dataIndex: 'jsonUrl'
}, {
header: 'Group Text Template',
sortable: true,
dataIndex: 'groupTextTemplate'
}, {
header: 'Group Headers',
sortable: true,
dataIndex: 'groupHeaders'
}, {
header: 'Group Fields',
id: 'groupFieldsCol',
sortable: true,
dataIndex: 'groupFields'
}, {
header: 'Grouped Headers',
sortable: true,
dataIndex: 'groupedHeaders'
}, {
header: 'Fit to Screen',
sortable: true,
dataIndex: 'fitToScreen'
}, {
header: 'Ignore Cols',
sortable: true,
dataIndex: 'ignoreCols'
}, {
header: 'Get Row Class',
sortable: true,
dataIndex: 'getRowClass'
}
]),
initComponent: function() {
var ds = new Ext.data.DirectStore({
directFn: DirectReportDesigner.GetReports,
paramsAsHash: false,
paramOrder: 'start|limit|sort|dir',
root: 'data',
idProperty: 'id',
totalProperty: 'total',
sortInfo: {
field: 'title',
direction: 'ASC'
},
fields: [{
name: 'id'
}, {
name: 'title'
}, {
name: 'useGroupedColConfig'
}, {
name: 'groupTextTemplate'
}, {
name: 'groupHeaders'
}, {
name: 'groupFields'
}, {
name: 'groupedHeaders'
}, {
name: 'jsonUrl'
}, {
name: 'menuType'
}, {
name: 'actualType'
}, {
name: 'fitToScreen'
}, {
name: 'ignoreCols'
}, {
name: 'getRowClass'
}, {
name: 'isCopyOf'
}
],
remoteSort: true
});
var pager = new Ext.PagingToolbar({
store: ds,
displayInfo: true,
pageSize: this.pageSize
});
var config = {
store: ds,
bbar: pager
};
Ext.apply(this, Ext.apply(this.initialConfig, config));
Ideal.ReportDesigner.ReportGrid.superclass.initComponent.apply(this, arguments);
}
});
the grid renders ok, the server code to get the json fires ok, but the store never loads the data. i know it's being passed back as i can see it in firebug and that's how i pasted it above.
can anyone see anything obvious here?
cheers
w://
I've always defined store's fields as an array of strings, not as objects.
fields: ['id','title','useGroupedColConfig', ...]
i managed to sort this - it was the name of the c# variable that was getting serialized that was throwing it - why i have no idea!!!