Extjs 5.1 Dynamic addition of container to panel - javascript

What i am trying to do is dynamically add container to panel on click of button.
1st instance of container gets added and can be seen in the panel.items.length
2nd instance onwards the panel.items.length doesn't change. but the panel can be seen in dom and on screen.
Just wanted to know why the panel.items.length is not increasing. Is it a bug?
Fiddler link https://fiddle.sencha.com/#fiddle/p3u
Check for the line :
console.log(qitems);
below debugger; it is set to questionsblock.items.length that i am talking about.

Remove the itemId from QuestionTemplate and remove renderTo from the new instance.
Your click handler should look like this:
listeners: {
'click': function(button) {
var questionPanel = button.up('form').down('#questionsblock'),
qitems = questionPanel.items.length,
questiontemplate = Ext.create('QuestionTemplate', {
qid: qitems,
questiontype: 'text'
});
console.log(qitems);
questionPanel.add(questiontemplate);
questionPanel.doLayout();
}
}
Check this fiddle: https://fiddle.sencha.com/#fiddle/p47

Related

Creating Dynamic Tooltip for GridView in ASP.NET MVC

I have a GridPanel component in my EXT.NET MVC project, and I would like to create a dynamic tooltip that will display the text/data in each cell when hovered over. Since the .ToolTips() component isn't compatible with this, I am using JavaScript to try to render a dynamic tooltip. My current code creates HTML elements, and then adds tooltips to them:
var el = Ext.getBody().createChild({
html: '<div data-num="1" class="item">Foo</div>' +
'<div data-num="2" class="item">Bar</div>' +
'<div data-num="3" class="item">Baz</div>' +
'<div class="notip">No tip here</div>'
});
new Ext.tip.ToolTip({
target: el,
delegate: '.item',
listeners: {
beforeshow: function (tip) {
var current = tip.currentTarget.dom;
tip.setHtml('Item #' + current.getAttribute('data-num'));
}
}
});
And here is the code for the GridPanel I want to attach it to:
Html.X().GridPanel()
.Title("Request Priorities")
.ID("reqPrioritiesGrid")
.ColumnWidth(1)
.MarginSpec("0 0 0 0")
.Flex(1)
.ToolTips(t => t.Add(Html.X().ToolTip().Html("hello").ID("storeTip").Target("App.storeReqPriorities")))
.Border(true)
.Store(
Html.X().Store()
.ID("storeReqPriorities")
.AutoLoad(true)
.DataSource(Model.RequestPriorities)
.Model(
Html.X().Model()
.Fields(f =>
{
f.Add(Html.X().ModelField().Name("RequestPriorityKey").Type(ModelFieldType.Int));
f.Add(Html.X().ModelField().Name("RequestPriorityName").Type(ModelFieldType.String));
f.Add(Html.X().ModelField().Name("RequestPriorityDescription").Type(ModelFieldType.String));
f.Add(Html.X().ModelField().Name("SortOrder").Type(ModelFieldType.Int));
f.Add(Html.X().ModelField().Name("ResponseTarget").Type(ModelFieldType.String));
f.Add(Html.X().ModelField().Name("ResponseFormat").Type(ModelFieldType.String));
f.Add(Html.X().ModelField().Name("ResponseSLA").Type(ModelFieldType.String));
})
)
.ServerProxy(
Html.X().AjaxProxy()
.Url(Url.Action("ManageLists_GetRequestPriorities", "Admin", new { area = "Cadence" }))
)
)
.Listeners(l =>
{
l.Select.Handler = "handleReqPopulate(record.data);" + "toggleEditRequest();" + "resetAddNew();";
})
.ColumnModel(
Html.X().Column().Flex(1).Text("Request Priority Name").DataIndex("RequestPriorityName"),
Html.X().Column().Flex(3).Text("Request Priority Desciption").DataIndex("RequestPriorityDescription"),
Html.X().Column().Flex(1).Text("Sort Order").DataIndex("SortOrder"),
Html.X().Column().Flex(1).Text("Response Target").DataIndex("ResponseTarget"),
Html.X().Column().Flex(1).Text("Response Format").DataIndex("ResponseFormat"),
Html.X().Column().Flex(1).Text("Response SLA").DataIndex("ResponseSLA")
)
Is there a method similar to .createChild() used in the JavaScript above that can attach a tooltip to an element that is being dynamically created in MVC?
You can bind the ToolTip component to the grid's view with a custom show handler that would fetch the cell data (or row, or entire grid) and show the way you instruct. Wouldn't that suffice for your scenario?
In this case you won't be creating child tooltips though, but rather using the same tooltip to show specific data depending on where you hover the mouse over.
Add this after the grid -- yes, outside it. Given your code snippets, the ToolTip component declaration should look like this:
#(Html.X().ToolTip()
.Target("={App.reqPrioritiesGrid.getView().el}")
.Delegate(".x-grid-cell")
.TrackMouse(true)
.Listeners(l => l.Show.Handler="onShow(this, App.reqPrioritiesGrid)")
)
Then have a handler fill the tooltip's contents like this:
var onShow = function (toolTip, grid) {
var view = grid.getView(),
store = grid.getStore(),
record = view.getRecord(view.findItemByChild(toolTip.triggerElement)),
column = view.getHeaderByCell(toolTip.triggerElement),
data = record.get(column.dataIndex);
toolTip.update(data);
};
From this point, you could further customize the show function to build the tooltip the way you need it.
A grid with a per-cell tooltip is showcased in Ext.NET examples (WebForms) at Miscellaneous > Tooltips > GridPanel Cell Tooltip.
Hope this helps!

How to know/capture the Detail Grid ID of the specific detail grid you are in? (ag-grid javascript)

I have a Master-Detail ag-grid. One column has checkboxes, (checkboxSelection: true). The details grid have a custom status panel with a button. When the user clicks the button in any specific Detail grid, I don't know how to get the SelectedRows from just that one specific detail grid.
The problem is they might leave multiple details displayed/open, and then looping over each Detail Grid will include results from all open grids. I'm trying to isolate to just the grid where the user clicked the button.
I tried looping through all displayed/open detail grids to get the Detail grid ID. But I don't see any info in this that shows me which one they clicked the button in.
I tried in the button component to see if, in the params, there is anything referencing the detailgrid ID that the button is in, but I did not see anything there either.
This is the button component:
function ClickableStatusBarComponent() {}
ClickableStatusBarComponent.prototype.init = function(params)
{
this.params = params;
this.eGui = document.createElement('div');
this.eGui.className = 'ag-name-value';
this.eButton = document.createElement('button');
this.buttonListener = this.onButtonClicked.bind(this);
this.eButton.addEventListener("click", this.buttonListener);
this.eButton.innerHTML = 'Cancel Selected Records <em class="fas fa-check" aria-hidden="true"></em>';
console.log(this.params);
this.eGui.appendChild(this.eButton);
};
ClickableStatusBarComponent.prototype.getGui = function()
{
return this.eGui;
};
ClickableStatusBarComponent.prototype.destroy = function()
{
this.eButton.removeEventListener("click", this.buttonListener);
};
ClickableStatusBarComponent.prototype.onButtonClicked = function()
{
getSelectedRows();
};
Here is the code to loop through and find all open detail grids:
function getSelectedRows()
{
this.gridOptions.api.forEachDetailGridInfo(function(detailGridApi) {
console.log(detailGridApi.id);
});
I was able to work this out, so thought I'd post my answer in case others have the same issue. I'm not sure I took the best approach, but it's seemingly working as I need.
First, I also tried using a custom detail cell renderer, as per the documentation, but ultimately had the same issue. I was able to retrieve the DetailGridID in the detail onGridReady function--but couldn't figure out how to use that variable elsewhere.
So I went back to the code posted above, and when the button was clicked, I do a jquery .closest to find the nearest div with a row-id attribute (which represents the the DetailgridID), then I use that specific ID to get the rows selected in just that detail grid.
Updated button click code:
ClickableStatusBarComponent.prototype.onButtonClicked = function()
{
getSelectedRows(this);
};
Updated getSelectedRow function:
function getSelectedRows(clickedBtn)
{
var detailGridID = $(clickedBtn.eButton).closest('div[row-id]').attr('row-id');
var detailGridInfo = gridOptions.api.getDetailGridInfo(detailGridID);
const selectedNodes = detailGridInfo.api.getSelectedNodes()
const selectedData = selectedNodes.map( function(node) { return node.data })
const selectedDataStringPresentation = selectedData.map( function(node) {return node.UniqueID}).join(', ')
console.log(selectedDataStringPresentation);
}

Component lost during rerender, how to reattach?

I am rendering a component into a grid rowExpander plugin rowBodyTpl:
plugins: [{
ptype: 'rowexpander',
rowBodyTpl : [
'<div id="contact-row-{Id}"> </div>'
]
}],
var row = 'contact-row-' + record.get('Id'),
grid = Ext.getCmp(gridId),
if(!grid) me.createSubGrid(record,gridId).render(row);
This works fine. But when the grid receives an update event for a record with certain modifiedFields, that record's rowExpander is rerendered using the rowTpl only, and the inner grid is dangling somewhere. I can access the grid using Ext.getCmp, and grid.rendered is true, but it is not shown. So I guess I have to reattach the grid after the row has been rerendered.
I think I can attach to the update event, and find out whether the rowTpl has been rerendered without the child grid using
if(!grid.container.contains(grid.el))
But is there a way to put the grid back into the dom?
I have tried
grid.container.insertFirst(grid.el);
but this does not work. The element is inserted but the grid is not displayed.
Any ideas?
The way you are doing leads to memory leaks (because your component is not destroy when the grid is re-render).
I suggest to check at : Component Template (http://skirtlesden.com/ux/ctemplate) or if you try to render a nested grid, there was several attempt to build something correct and I think a working one is the following : http://blogs.walkingtree.in/2015/06/30/nested-grid-in-sencha-ext-js/
With my trials, I already was on the right track, and the error was somewhere else entirely. The problem was that my update event fn which did the reattach was executed before the update event fn that broke everything, because the fn was fired on the same event and had the same priority, but was attached to the store earlier. Changing the priority was one option, but I just put the creation into the boxready event, which is executed after the view has attached its events to the store:
xtype:'grid',
listeners:{
boxready:function(grid) {
var store = grid.getStore();
...
store.on({
update:function(store, record) {
me.restoreSubgridDom(record);
},
beforeload:function(store) {
var records = store.getRange();
Ext.each(records,me.destroySubgrid);
}
});
}
}
with the two functions:
restoreSubgridDom: function(record) {
var row = 'contact-row-' + record.get('Id'),
gridId = 'ContactRow'+record.get('Id')+'Grid',
grid = Ext.getCmp(gridId);
if(grid && !grid.container.contains(grid.el))
{
grid.container.insertFirst(grid.el);
}
},
destroySubgrid: function(record) {
var gridId = 'ContactRow'+record.get('Id')+'Grid',
grid = Ext.getCmp(gridId);
if(grid) grid.destroy();
}

Extjs 4.1.1a Check symbol of Checkbox on grid panel doesn't work

on a tab panel I create a tab for each year I have in a database (in this case the database contains at the moment only 3 years: 2012, 2013 ans 2014) and finally I set as active tab the current year (2013). In the controller I do the following:
var tp= this.getTpOverview();
this.getPlannedYearsStore().load({
callback: function(records) {
for (i=0; i< records.length; i++){
var year = records[i].data.year;
var tab = tp.add({
title: year,
year: year,
layout:'fit',
listeners: {
activate: function() {
var tbOverview = Ext.getCmp('tabOverview-'+ this.year);
if (!tbOverview) {
var gridOverview = Ext.create('WLPT.view.CPAssMonthActHours', {
id: 'tabOverview-' + this.year,
year: this.year,
xtype: 'cpassmonthacthoursview',
autoScroll: true
});
this.add(gridOverview);
} else {
selectedYear = this.year;
tbOverview.getStore().load({
params : {
wrk_year: selectedYear
}
});
}
}
}
});
if (currentYear == parseInt(records[i].data.year)) {
tab2Activate = tab;
}
}
tp.setActiveTab(tab2Activate);
}
});
When I run the application this seams to work fine.
I forgot to say that each tab contains a grid panel with a check column (Checkbox model) and for each item (row) a cell editor is setted on selected cells.
The active tab (2013) works fine. I can check the checkboxes to perfom a sum of the selected items. Indeed, the cell editor works fine.
The problem appears when I change the tab. The corresponding grid comes with the checkbox column. But on the javascript console appears the following error message:
Uncaught TypeError: Cannot call method 'setWidth' of undefined ext-all-debug.js:95689
Ext.define.onColumnResize ext-all-debug.js:95689
Ext.define.onColumnResize ext-all-debug.js:101362
Ext.util.Event.Ext.extend.fire ext-all-debug.js:8896
Ext.define.continueFireEvent ext-all-debug.js:9102
Ext.define.fireEvent ext-all-debug.js:9080
Ext.override.fireEvent ext-all-debug.js:51104
Ext.define.onHeaderResize ext-all-debug.js:97344
Ext.define.afterComponentLayout ext-all-debug.js:98063
Ext.define.notifyOwner ext-all-debug.js:28381
Ext.define.callLayout ext-all-debug.js:103511
Ext.define.flushLayouts ext-all-debug.js:103680
Ext.define.runComplete ext-all-debug.js:104194
callOverrideParent ext-all-debug.js:54
Base.implement.callParent ext-all-debug.js:3813
Ext.override.runComplete ext-all-debug.js:21234
Ext.define.run ext-all-debug.js:104175
Ext.define.statics.flushLayouts ext-all-debug.js:21238
Ext.define.statics.resumeLayouts ext-all-debug.js:21246
Ext.resumeLayouts ext-all-debug.js:23343
Ext.define.setActiveTab ext-all-debug.js:111589
Ext.define.onClick ext-all-debug.js:111357
(anonymous function)
Ext.apply.createListenerWrap.wrap
Despite that, the grid is shown correctly. But, when I select a item the javascript console shows the following error message:
Uncaught TypeError: Cannot call method 'up' of null ext-all-debug.js:99591
Ext.define.onRowFocus ext-all-debug.js:99591
Ext.util.Event.Ext.extend.fire ext-all-debug.js:8896
Ext.define.continueFireEvent ext-all-debug.js:9102
Ext.define.fireEvent ext-all-debug.js:9080
Ext.override.fireEvent ext-all-debug.js:51104
Ext.define.focusRow ext-all-debug.js:92462
Ext.define.onRowFocus ext-all-debug.js:92423
Ext.define.onLastFocusChanged ext-all-debug.js:109495
Ext.define.setLastFocused ext-all-debug.js:83855
Ext.define.doMultiSelect ext-all-debug.js:83761
Ext.define.doSelect ext-all-debug.js:83721
Ext.define.selectWithEvent ext-all-debug.js:83623
Ext.define.onRowMouseDown ext-all-debug.js:109750
Ext.util.Event.Ext.extend.fire ext-all-debug.js:8896
Ext.define.continueFireEvent ext-all-debug.js:9102
Ext.define.fireEvent ext-all-debug.js:9080
Ext.override.fireEvent ext-all-debug.js:51104
Ext.define.processUIEvent ext-all-debug.js:85315
Ext.define.handleEvent ext-all-debug.js:85227
(anonymous function)
Ext.apply.createListenerWrap.wrap
The selection on the item fires the event 'select' and 'deselect' when I click a second time. But the check symbol on the checkbox doesn't work any time.
I have thougth to put this symbol manually on the events 'select' and 'deselect' as a workaround, but I don't know how to put this style and which one is.
Do you have any ideas? Look forward for your suggestions. Thank you in advance.
Manuel
I think, the errors are not related to the code you posted. In fact, your code does not set the width, nor does it call up.
I find your code convoluted: a callback with a listener inside, that creates a view inside. And I don't understand if your code is inside a controller or another class.
Here is a problem:
var tab = tp.add({
//xtype is missing
title: year,
For debugging, I can giv you the following recommendation:
Use ext-dev.js instead of ext-all-debug.js. This will load all required classes one after the other, and the errors in the backtrace are not all inside ext-all-debug.js, but each line shows the line in the source class with all comments in it.
To get a cleaner programming style, try to follow the MVC pattern strictly:
Folder structure as recommended
Define events in the controller, like
init: function(){
this.listen({
store: {
'#plannedYearsStore': {load: this.onPlannedYearsStoreLoad}
}
})
this.control({
'tab': {activate: this.onTabActivate}
})
},
onPlannedYearsStoreLoad: function (store, records){
for (i=0; i< records.length; i++){
var year = records[i].data.year;
var tab = tp.add({
...
},
onTabActivate: function (){
var tbOverview = Ext.getCmp('tabOverview-'+ this.year);
...
},
If possible, define your tab in a view class in a separate file.
When you adhere striclty to this MVC structure, you will get a much easier maintainable code.

Problem with ExtJs editor grid panel

I've an extjs editor grid panel(3.3.1) that is binded to a store. New records are added to the grid by an empty row at the top. On the load of the store I'm adding an empty row at the top of the grids. When the user adds a new value and the focus loses out I'm adding another empty row.
AV.ClassifiedCategories = Ext.extend(Ext.grid.EditorGridPanel, {
....
initComponent: function(){
this.store = this.initialConfig.store;
//add an empty row at top
this.store.on('load', this.addCategory, this);
Ext.apply(this,
{
clicksToEdit: 1,
listeners:
{
afteredit : function(e){
this.addCategory();
},
scope: this
}
});
},
//adds an empty row and insert a record to store
addCategory: function(){
var Category = this.getStore().recordType;
var cat = new Category({ cat_id: null, cat_name: "" });
this.stopEditing();
this.store.insert(0, cat);
this.startEditing(0, 0);
return cat;
},
...
});
The problem is facing here is once the afteredit event is fired and an empty row is added the focus is not moving to the first row i.e. the second row is still in edit mode. How I can solve that?
I've taken your code and have created this demo. As you can see everything works as expected. Are you sure you have provided us with non-working code?

Categories