I am using an external JS Widget library called jqWidgets mainly for their feature rich GRIDS. I am building a Single Page Application that adds and removes LOTS of grids throughout the use of the application. I am having a problem with the DOM Node Count increasing, I've managed to make a dent in the Event Listener Count, although that is slowly creeping up as well. Example:
Javascript:
$(document).ready(function () {
$("#runTest").on('click', function(){
$("#testGrid").jqxGrid({
width: 795,
selectionmode: 'singlecell',
editable: true,
sortable: true,
filterable: true,
rowsheight: 20,
height: 200,
columns: [
{text: 'Activity ID', datafield: 'activity_id', width: 150},
{text: 'Description', datafield: 'activity_description', width: 150},
{ text: 'Notes ⁄ Comments', datafield: 'activity_notes'}
]
});
});
$("#destroyGrid").on('click', function(){
$("#runTest").off('click');
$("#testGrid").jqxGrid('destroy');
$("#testDiv").remove();
});
});
HTML:
<div id='testDiv'>
<div id='testGrid'></div>
</div>
<input type="button" value="click me" id="runTest" />
<input type="button" value="destroy" id="destroyGrid" />
When click the runTest button to create the grid, my DOM Node Count goes from 318 to 880 and Event Listener Count from 8 to 132.
After I click the destroy button (and Garbage Collection occurs), the DOM Node Count goes from 880 to 645and Event Listener Count from 132 to 32.
Theoretically shouldn't the values return to the original state? Am I missing something here? I've read through tons of posts on this subject and I seem to be following the standard practices so I am tempted to think this is an issue with the jqWidget library and not my code, any help or advice is appreciated.
I've tried empty() and remove() with the same results.
Related
I have a problem with fieldsets show and hide functions.
In my app at the left side I have a combobox with change listener. At the right side I have several different textfields which are showing and hiding according as chosen value in combobox.
Every hide and show functions are working with fieldsets, but if I can't to show/hide fieldset. Fieldset reference is visible, I can list this component with console.log() function.
Here's a piece of my code:
var rigthPanelLeftContainer = {
flex: 1,
minWidth: 200,
defaults: {
xtype: 'textfield',
minWidth: 180,
anchor: '100%'
},
items: [
//some working textfields here
{
xtype: 'fieldset',
labelWidth: 160,
anchor: '100%',
height: 40,
itemId: 'remarkId',
title: 'title'],
hidden : !ifHideIt, //boolean
items: [{
xtype: 'text',
height: 25,
text: 'sometext']
}]
}
]};
var comboBoxConnectors = {
xtype: 'combobox',
fieldLabel: Ext.translations.map['field.label.common'],
store: Ext.state.Manager.get('conTypes'),
editable: false,
queryMode: 'local',
name: 'conType',
itemId: 'conTypeField',
value: connObj === null ? conTypes[0] : connObj.type,
labelWidth: 160,
anchor: '100%',
listeners: {
change: function(obj, newValue, oldValue) {
//many hide/show working on textfield functions
var remarkId = me.query('#remarkId');
console.log(remarkId); //returns my fieldset element
remarkId.hide(); //returns remarkId.hide is not a function
}
}
}
I really need your help guys, whats wrong with this?
In your code, you have a comment that says that me.query( '#remarkId' ) returns your fieldset element. This is not technically correct. Assuming that me.query() is a component query, what you are actually getting in return is an array of matched components. So then, you're getting the undefined function error because, most definitely, an array does not have a hide() method. If you access the first element in the array and then call the hide() method, it should work.
However, you should probably also consider going about this a bit differently. Instead of getting an array of elements with query() (which may always be one, but not necessarily...), you could use the built in traversal methods to find the correct component. For example, assuming that the combobox and the fieldset are both children of the same form panel, you could do something like this: mycombobox.up( 'form' ).down( 'fieldset#remarkId' ). This basically instructs the code to traverse up the component hierarchy to the nearest form, then to drill down to the first descendant of the form that is a fieldset with the itemId of "remarkId". This will only ever give you a single component as a result, so you don't have to bother with accessing a component out of an array of components.
I working on a kendo ui grid. The grid is not-editable as default.
In the toolbar is a 'edit' button. When the user clicks on it, the grid should be editable in batch mode like this.
The only solution to get this work is remove and recreate the grid/datasource with new properties (editable:true etc).
This works as expected. Now I want to set the focus on the first row/cell, so that the user can see that the grid is editable now (in the example below the row becomes an input field).
Any suggestions for this?
Here is a fiddle for this.
$('.k-grid-edit').on('click', function (e) {
e.preventDefault();
// remove old grid
$('#grid').html('');
// recreate grid with edit: true and new datasource
$('#grid').kendoGrid({
dataSource: dataSourceInEdit,
editable: true,
columns: [{
field: 'TableId',
title: 'Id',
width: 50
}, {
field: 'Area',
title: 'Area'
}, {
field: 'Table',
title: 'Table',
width: 60
}, {
command: 'destroy',
title: ' ',
width: 100
}]
}).data("kendoGrid");
}); // end edit
Okay, I got it:
These 2 lines make it happen:
var grid = $("#rt_tableGrid").data("kendoGrid");
grid.editRow($("#rt_tableGrid tr:eq(1)"));
Certainly only on my local script, in the Fiddle I cant´t get it to work.
Although in the Docu is written: Requires "inline" or "popup"
Documentation here
Using Kendo there are two ways to initialize a Kendo Widget:
one:
<span id=”UniqueID” /></span>
<script>
$(“#UniqueID”).KendoWidget();
</script>
two:
<span id=”UniqueID” data-role=”Widget” /></span>
<script>
Kendo.init($(“#UniqueID”));
</script>
Does anybody know the pro's and con's of there two methods?
I want to make sure I am aware of the implications of any specific direction.
and if it's more of less equal, which is the most commonly found mechanism, dev's follow.
Kind Regards,
Flippie
I use both. It depends on the complexity of the configuration for that widget, and in some cases, it's not possible (or at least very difficult) to initialize a widget within the HTML due to data context issues; thus, it's easier to initialize it in code. Other times, it's simply personal preference.
For all widgets, I'll start by declaring them in the HTML, like so:
<div id="cases"
data-role="grid"
data-bind="source: cases"
data-pageable="{ refresh: true }"
data-sortable="{ mode: 'multiple' }"
data-filterable="{
extra: false,
operators: { string: { contains: 'Contains', eq: 'Is equal to' } }
}"
data-columns="[
{ title: '', template: kendo.template($('#editColumnTemplate').html()), sortable: false, filterable: false, width: 42 },
{ field: 'number', title: 'Number', width: 160 },
{ field: 'subject', title: 'Subject' },
{ field: 'contact', title: 'POC', width: 200 },
{ field: 'referral', title: 'Referred By', width: 100 },
{ field: 'opened', title: 'Opened', format: '{0:d}', filterable: false, width: 120 },
{ field: 'closed', title: 'Closed', format: '{0:d}', filterable: false, width: 120 }
]">
</div>
I prefer doing it this way because all of the widget's configuration is declared inline with it's location in the HTML. It's similar in the way that you have to bind data to your view using MVVM frameworks like Kendo and Knockout, so, I like to be consistent. For me, it's easier to maintain because everything is defined in one place and it looks clean. Now, if I run into data context problems where I can't bind a particular observable or data element, say within this grid's columns definition, then I move it all to code.
Either way is more or less equal. I couldn't tell you which is more common. I imagine most developers do it the same way I do - mixing both methods.
I'm using ExtJS 4 (beta 3) and I have a TreePanel that is my kind of navigation menu.
It is something like this:
Jobs
Add Job
List All Jobs
...
...
...
(this will be made on a permission system base, but that's another story)
On ExtJS 3, do something when i clicked "Add Job" was as simple as adding
...
leaf:true,
listeners:{
click:function(n){
//my code...
}
}
...
to the root children elements.
Now It's not that simple. The closer i got was with (on the treepanel)
listeners:{
click : {
element : 'el',
fn : function(eve, elem, obj){
console.log(node);
console.log(elem);
console.log(obj);
}
}
}
So, maybe i'm just a noob, maybe i have already a strong hatred for ExtJS, maybe is just a problem in this beta version, but...
How do I add a listener to the click event on the tree nodes? (the Select event won't do what i need)
Thank you guys.
EDIT: Currently testing with this, and it's not working.
... = Ext.create('Ext.tree.TreePanel', {
region : 'west',
collapsible : false,
title : 'ITMI',
width : 220,
margins : '5 5 5 5',
cmargins : '5 5 5 5',
hideHeaders : true,
useArrows : true,
rootVisible : false,
headers: [{
xtype : 'treeheader',
text : 'Nome',
flex : 1,
dataIndex: 'nome'
}],
store: store,
listeners:{
itemclick: function(n){
console.info(n);
}
}
...
EDIT 2: The itemclick event now works (on EXJS 4 final), It still doesn't solve my problem. I'd Like to call a specific function when i call each treenode. Before it was really easy. Now i can't figure it out.
in ext4 beta3 (maybe in final release too)... there is no longer click event....
this has changed to itemclick more info
var tree = Ext.create('Ext.tree.Panel', {
store: store,
renderTo: Ext.getBody(),
height: 300,
width: 250,
title: 'Files',
listeners:{
itemclick: function(n){
console.info(n);
}
}
});
So, It may help some people who may be struggling with the same issue I did then.
The "itemclick" event is the way to handle leafs clicks, and it didn't work then for reasons I don't remember.
I accomplished what I needed by splitting the config I had in the database, something like
controllerName|functionName
and then call this code on the handler of the "itemclick:
this.getController(ctr)[fn]();
where ctr is the controllerName and fn is the functionName. This could easily be done with eval, but I prefer not to.
I could not get itemclick to fire with IE (fine in Chrome). I modified my code to use 'checkchange' and it works fine.
I'm loading a jqGrid on my page. The grid has a Delete button for each row. I'm trying to use the jquery UI dialog confirmation on my Delete button.
Here's my javascript code:
<script type="text/javascript">
$(document).ready(function () {
$("#list").jqGrid({
url: '/MyController/MyFunction/',
datatype: 'json',
mtype: 'POST',
colNames: ['', 'Name', ''],
colModel: [
{ name: 'Edit', index: 'Edit', width: 40, align: 'left', sortable: false },
{ name: 'Name', index: 'Name', width: 120, align: 'left' },
{ name: 'Delete', index: 'Delete', width: 50, align: 'left', sortable: false }],
pager: $('#pager'),
rowNum: 10,
rowList: [10, 20, 50],
sortname: 'Name',
sortorder: "asc",
viewrecords: true,
width: 700
});
$("#dialog-confirm").dialog({
autoOpen: false,
modal: true,
buttons: {
"Delete": function () {
window.location.href = $(this).attr("href"); ;
},
Cancel: function () {
$(this).dialog("close");
}
}
});
$("a.confirm").click(function () {
alert("HELLO");
//$("#dialog-confirm").dialog("open");
});
});
</script>
I'm passing in data from my controller to the grid. I have the class "confirm" added to the Delete link for each row.
If I click on my Delete button, nothing happens. The link has the correct class, and all my javascript is loading correctly. I placed an alert at the end of my document.ready function to make sure there were no errors.
But if I comment out my jqGrid and add a link onto my page with the class "confirm", the click event will fire.
Has anyone ever run into this?
The main problem which you have is that you try to make 'click' binding with $("a.confirm").click(...) before the elements "a.confirm" are loaded.
You should either place the binding code inside of loadComplete or gridComplete event handler or use jQuery.live
$("a.confirm").live('click', function() {
alert("HELLO");
//$("#dialog-confirm").dialog("open");
});
instead of $("a.confirm").click(...).
One more general remark. The best practice working with jqGrid is dividing data from the HTML markup. I suppose that you place HTML fragment with <a class="confirm">...</a> inside of JSON data returned from the server. jqGrid supports another ways to archive the same results. You can 1) use showlink formatter; 2) use custom formatter which allow create any HTML fragment for the grid cell based on the row of data (see rowObject parameter) returned from the server 3) use unobtrusive JavaScript (see my answer with the code example) 4) any mix from both (see another answer with the code example). The way 3 seems me mostly close to what you do.
In any way having clear separation of JSON data from HTML markup is good not only because of design reason. It allows additionally reduce the size of data send from server. (see this answer for more information)