ExtJS4 - Rendering a subgrid - extjs

I'm trying to create a grid inside a grid row when I expand the row using the rowexpander plugin. How do I render the subgrid on the expandbody event?
This is my code so far, it is used as an event handler property when I define my grid panel:
getOtherProducts: function (rowNode, record, expandRow, eOpts) {
$.ajax({
type: 'GET',
url: "Report.aspx/GetOtherProducts",
data: { ID: record.data['ID'] },
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function () {
var subStore = Ext.create('pr.store.Store-Products');
subStore.proxy.extraParams.productID = record.data['ID'];
var subGrid = Ext.create('Ext.grid.Panel', {
store: subStore
});
subGrid.getEl().swallowEvent(['mouseover', 'mousedown', 'click', 'dblclick']);
},
error: function () {
showNotificationBar("Error retrieving product data. Re-expand the row to try again.");
}
});
},

stratboogie's answer at http://www.sencha.com/forum/showthread.php?151442-Nested-EXTJS-4-Grids did the job.
I made a slight modification to store the Element ID into an array
subGrids.push(subGrid.id);
and then overrode paging event handlers to loop through the array and destroy all elements with the IDs inside the array to keep memory in check.
function destroySubGrids(){
Ext.each(subGrids, function(id){
var subGrid = Ext.getCmp(id);
if(subGrid){
subGrid.destroy();
delete subGrid;
}
});
subGrids = [];
console.log(Ext.ComponentMgr.all.length); //debug
}

Related

Extjs 5.1.2 Listeners on a dynamically generated element

I am creating a page which will dynamically generate collapsed panels. When a user expands these panels, it will perform a GET request and populate this generated panel with the JSON response. The idea is to perform a sort of lazy-load or as-needed load, as the amount of data that would be shown initially can get overwhelming.
However, I can't seem to get the listeners for my panels to work.
Here is the code, which generates the panels through a button's click function:
xtype : 'button',
listeners : {
click : function (button, e, eOpts) {
console.log("Click function");
Ext.Ajax.request({
url: 'data/Countries.json',
success: function(response, options) {
var data = Ext.JSON.decode(response.responseText).results;
var container = Ext.getCmp('panelContainer');
container.removeAll();
for (i = 0; i < data.length; i++)
{
container.add({
xtype: 'panel',
title: 'Country Name - ' + data[i].countryName,
collapsible: true,
listeners: {
expand: function() {
Ext.Ajax.request({
url: 'data/CountryData.json',
success: function(response, options) {
var data = Ext.JSON.decode(response.responseText).results;
var me = this;
me.add({
xtype: 'grid',
store: Ext.create('Ext.data.Store',
{
fields : [{
name: 'gdp'
}, {
name: 'rank'
}, {
name: 'founded'
}, {
name: 'governor'
}, {
name: 'notes'
}], //eo fields
data: data.information,
}),// eo store
columns: [
{ text: 'GDP', dataIndex: 'gdp'},
{ text: 'rank', dataIndex: 'rank'},
{ text: 'Date', dataIndex: 'founded'},
{ text: 'name', dataIndex: 'governor'},
{ text: 'Notes', dataIndex: 'notes', flex: 1, cellWrap: true}
], //eo columns
autoLoad: true
});
},
failure: function(response, options) {}
});
},
collapse: function() {
console.log("Collapse function");
var me = this;
me.removeAll();
}
}//eo panel listeners
});//eo cont.add()
}//eo for loop
}, //eo success
failure: function(response, options) {
//HTTP GET request failure
}//eo failure
});//eo Ajax request
} //eo click
}//eo button listeners
Originally, the panels were dynamically generated along with their populated grids from the click event, which worked perfectly. By wrapping the grid creation in a listener on the dynamically generated panel to create a load-as-needed, I can't get the expand or collapse listeners to trigger.
Searching around, one possible solution I haven't tried is to create a custom component and call it through its xtype rather than build everything in-line, which would let me define listeners there instead of nesting them in a function (this is better as well for readable and reusable code, but I'm just trying to get to the root of the issue for now).
Is there an issue with listeners on dynamically generated panels? What is the reason that the event triggers for collapse and expand aren't firing?
Thanks for all the help!
I'm still have a few issues, but as my main question was about firing the listeners, I'll write the solution I reached.
The issue I had was getting listeners to fire in a dynamically generated element. This led to nested listener functions, and I hadn't defined a scope. I had tried pagep's solution of setting the defaultListenerScope, but for me personally I didn't see a change.
I instead wrapped the listener functions into their own functions and called then through the listener like this:
listeners: {
expand: 'expandFunction',
collapse: 'collapseFunction'
},//eo panel listeners
expandFunction: function() {
//Do Ajax request and add grid to panel
},
collapseFunction: function() {
//Remove all child elements from this panel
}
Instead of doing this:
listeners: {
expand: function() {
//Do Ajax request and add grid to panel
},
collapse: function() {
//Remove all child elements from this panel
}
},//eo panel listeners
By wrapping the info this way, I was able (to a certain degree) to remove the nesting of listeners with generated elements. I also created a custom component and placed these listeners with the component I was generating. My only issue now is populating the generated element, since I am getting Uncaught TypeError: Cannot read property 'add' of undefined when trying to reference the itemId of my component.
My final simplified code, which generates a collapsed panel on button-click and populates it with generated data when expanded, looks like this:
//View.js
click: function (button, e, eOpts) {
Ext.Ajax.request({
url: 'data/Countries.json',
success: function(response, options) {
var data = Ext.JSON.decode(response.responseText).results;
var container = Ext.getCmp('panelContainer');
console.log(container);
container.removeAll();
for (i = 0; i < data.length; i++)
{
container.add({
xtype: 'customPanel',
title: data[i].country
});
}
});
//customPanel.js
Ext.define('MyApp.view.main.CustomPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.customPanel',
xtype: 'panel',
collapsible: true,
collapsed: true,
listeners: {
expand: 'expandFunction',
collapse: 'collapseFunction'
},//eo panel listeners
expandFunction: function() {
//Do Ajax request and add grid to panel
},
collapseFunction: function() {
//Remove all child elements from this panel
}
});

Is there a way to refresh virtual repeat container?

I've got a md-virtual-repeat-container that handles the data from an API call triggered by a search box. I'd like to be able to refresh this container when a user enters a second search query.
I'm using a setup similar to this plnkr which is from this question:. The only difference is its getting data from a server when the user enters a search term.
My Question
Is there a way to trigger a refresh an md-virtual-repeat-container?
I don't think the code is relevant but here's my (simplified) production code:
var self = this;
self.infiniteItems = {
numLoaded_: 0,
toLoad_: 0,
items: [],
getItemAtIndex: function (index) {
if (index > this.numLoaded_) {
this.fetchMoreItems_(index);
return null;
}
return this.items[index];
},
getLength: function() {
return this.numLoaded_ + 25;
},
fetchMoreItems_: function (index) {
if (this.toLoad_ < index) {
this.toLoad_ += 5;
var offset = 0;
$http({
method: 'GET',
datatype: 'json',
url: '{my-api-call}',
contentType: "application/json; charset=utf-8",
cache: false,
params: {
param: query,
page: offset
}
}).then(angular.bind(this, function (obj) {
this.items = this.items.concat(obj.data.SearchResults);
this.numLoaded_ = this.toLoad_;
this.offset++;
$scope.searchResults = obj.data.SearchResults;
}));
}
}
};
You can force a redraw of your md-virtual-repeat container by triggering a fake window resize event (this causes the directive to call its private handleScroll_() method which then calls containerUpdated()).
This will trigger a fake window resize event:
angular.element(window).triggerHandler('resize');
You can also use this to cause refresh of items in specific scope and not in the entire document:
scope.$broadcast('$md-resize')
Resetting the model should also work.
In your case you could a have a new function on infiniteItems:
refresh : function() {
this.numLoaded_= 0;
this.toLoad_ = 0;
this.items = [];
}
I'm going to post my solution since there isn't an answer yet. If an better answer gets posted I'll gladly accept it.
First, I migrated all of my search result code into it's own template, directive and controller.
Next, I added an empty container in place of my logic. I'll use this as a place to dump my directive dynamically every time I search.
`<div id="search-result-container"></div>`
Finally, I dynamically appended my new directive like this
$scope.handleHotlineSearchClick = function () {
var query = $('#legal-search-input').val();
if (query != "") {
$scope.searchLoaded = false;
$('#search-result-container').empty().append($compile("<search-result></search-result>")($scope));
}
};
This way every time the user enters a new search term the directive gets reloaded.

Kendo HierarchicalDataSource issue binding to Kendo treeview

I have a Kendo HierarchicalDataSource object bound to a Kendo treeview widget.
The HierarchicalDataSource simply returns a one-level-deep json formatted object, but for some reason it won't render in the treeview. It just shows the top node "Dimensions", but renders no data when expanded.
Here is my plunk treeview sample , which contains index.html and script.js .
FYI for script.js :
$scope.dimenDataSource is the Kendo HierarchicalDataSource object which uses the transport property to call my method getDimensionsFromServer2 and also specify the schema.
Another FYI: In getDimensionsFromServer2() I have two ways of returning my test data. The dataFlat var returns a flat array, which renders fine. The data object has nested data, but does NOT render in treeview.
I'm not sure what's going wrong.
Thank you,
Bob
**** UPDATE ****
The problem was the incorrect placement of the schema setting (see my answer):
settings.dimenDataSource = new kendo.data.HierarchicalDataSource({
transport: {
read: function(options){
datacontext.getDimensionsFromServer().then(function (data) {
var rootnode = [{ name: "Dimensions", items: data.data }];
options.success(rootnode);
});
},
schema: {
model: { children: "items" }
},
loadOnDemand: false
}
});
My mistake was in the schema placement, which I had inadvertently placed in the transport option. It should placed at the same level, not within it.
Here's is the corrected version:
settings.dimenDataSource = new kendo.data.HierarchicalDataSource({
transport: {
read: function(options){
datacontext.getDimensionsFromServer().then(function (data) {
var rootnode = [{ name: "Dimensions", items: data.data }];
options.success(rootnode);
});
},
loadOnDemand: false
},
schema: {
model: { children: "items" }
}
});

Backbone.js Click event firing multiple times

Is there any forum/Issue tracking website for backbone.js ?
I have an Issue that click event triggers multiple times. I had found a work around using Underscore.js , debounce method.
Is the problem addressed in latest backbone.js ?
Please suggest me on this .
Raja K
define([
'jquery', 'underscore','backbone',], function($, _, Backbone,Marionette) {
var Sample = Backbone.Marionette.ItemView.extend({
template: 'sample/sample',
model : new Model(),
render: function() {
id = utils.getStorage('some_id');
if(parseInt(id) > 0 ) {
this.model.set({some_id:id});
this.rendersome(id);
} else {
data = new Model().toJSON();
this.renderdata(data);
}
},
events: {
"click #some" : "someinfo"
},
someinfo : function() {
var self = this;
$.ajax({
url: API_URL + "sample/sampleinfo",
type: 'POST',
crossDomain: true,
cache: true,
data: JSON.stringify({ 'code1': this.model.get('code1'),
'code2' : this.model.get('code2'),
"auth" : init.auth, "user_id" : init.user_id }),
contentType: 'application/json',
success: function(data,response,jqXHR) {
if('SUCCESS' == data._meta.status && data.records.message.me == 'positive') {
self.model.set(data.records);
self.renderdata(data.records);
} else {
console.log(data.records.message);
return false;
}
},
error: function (request, status, error) {
console.log(request);
}
});
},
change: function (event) {
var target = event.target;
var change = {};
change[target.name] = target.value;
this.model.set(change);
},
});
return Sample;
});
Router Init code below,
routeaction : function() {
var Header = new HeaderView({'el': '#header'});
Header.render();
var test = new Tview({'el': '#content'});
test.render();
}
UPDATE : I am using backbone.subroute and the view got destroyed but not rendering after that. Becuase both old and current object referring the same element. But why it is not rendering again ? Can you please suggest me what I am missing here ?
render: function () {
// remove the existing header object
if(typeof gheader == "object") gheader.close();
// render the object
self.$el.html(tmpl(data));
},
UPDATE : I guess view.remove() is working fine. I have reused the container at $el and view.remove() removed the container element and stopped rendering the other views. Should I recreate the container ?
I can use "tagName" but suggest me how do I apply the stylesheet ?
undelegateEvents() Removes all of the view's delegated events. Useful if you want to disable or remove a view from
the DOM temporarily.
http://backbonejs.org/#View-undelegateEvents

How to reload carouse items onPainted? Sencha touch

I would like to reload items in the carousel onPainted() method. So whenever users come the carousel item then we have a fresh list of carousel items. Problem at this point of time (please have a look at the source code), the carousel reloads items, however until I touch the carousel, the first carousel item is blank (or not selected) and no items selected. I would like at least to see the first element to be selected.
So here is the simplified source code:
Ext.define("APN.view.FeaturedCarousel", {
config: {
listeners: {
painted: function(carousel, eOpts) {
var features_url = Ext.getStore("regionalisation").getRegionalisedMenus().feature.url;
this.setCarouselStore(features_url);
}
}
},
initialize: function () {
this.callParent();
var me = this;
var features_url = Ext.getStore("regionalisation").getRegionalisedMenus().feature.url;
this.setCarouselStore(features_url);
},
setCarouselStore: function (features_url) {
var me = this;
Ext.Ajax.request({
url: features_url,
success: function (response) {
me.removeAll();
if (!xml) return;
var store = Ext.create('Ext.data.Store', {
autoLoad: true,
fields: [
],
data: xml,
proxy: {
type: 'memory',
reader: {
type: 'xml',
rootProperty: 'xml',
record: 'item'
}
}
});
store.each(function (record) {
var item = Ext.create("Ext.Container", {
html: "some HTML HERE"
});
me.add(item);
});
}
});
}
});
I think you should activate the first item in the carousel once all the items are added. Like this:
store.each(function (record) {
var item = Ext.create("Ext.Container", {
html: "some HTML HERE"
});
me.add(item);
});
me.setActiveItem(0);
This should make the first item selected.
If you want to change the carousel content every time it is activated, use "active" listener. Because "painted" will be called only once and if you want that, then no point in adding a painted event because you are already calling the "setCarouselStore" function in "initialize" method.

Resources