ExtJS store add calls both create and destroy - javascript

this.store = Ext.create('Ext.data.Store', {
fields: [
'id',
'name',
'Address',
'status',
],
autoLoad: auto,
autoSync: auto,
remoteSort: true,
proxy: {
type: 'ajax',
api: {
create: '../../create.php',
read: '../../read.php',
destroy: '../../destroy.php',
update: '../../update.php'
},
reader: {
type: 'json',
root: '__data',
totalProperty: 'grandTotal'
},
writer: {
type: 'json',
root: '__data'
},
listeners: {
exception: function( t, response, op ) {
var _da = Ext.decode( response.responseText );
if( _da ) {
if( _da.message == "ExistingName" ) {
_da.message = Locale.gettext('name already exists');
} else {
frm = _self.subnetEditor.down('form');
name_field = frm.down('textfield[name=name]');
}
name_field.markInvalid(Locale.gettext(_da.message));
}
showMsg( _da.success, _da.message );
if( op.action == 'create' || op.action == 'update' ) {
_self.store.rejectChanges();
_self.store.load();
}
}
}
}
}
});
This is the store that calls four php files to do the CRUD, and some listener to process the duplicate name.
removeSelected: function() {
var _self = this;
Ext.Msg.show( {
title: Locale.gettext( 'Remove selected?' ),
msg: Locale.gettext( 'Are you sure you want to remove ALL SELECTED items?' ),
icon: Ext.Msg.WARNING,
buttons: Ext.Msg.OKCANCEL,
buttonAlign: 'right',
fn: function( button ) {
if( button == 'ok' ) {
var grid = _self.down( 'grid' );
if( grid ) {
var selection = grid.getSelectionModel().getSelection();
if( selection.length ) {
_self.store.remove( selection );
if( _self.useGridRowEditing ) {
_self.store.sync();
}
}
}
}
}
} );
}
Here is the remove function will remove the selected items, and I have store.add(item) to add records. But the problem is if I run the remove function, and then store.add to add any items, the store.add will fire create and destroy together. The second destroy will post exact data as the first time when I run the remove function.
I suppose that the store.add will only call the create api in the proxy, but why destroy has been called?
I see the remove throws an exception. If an exception has been thrown, is that mean the remove action is still pending? So it batch the add and remove together?

This is not caused by the ExtJS, it causes the server respond "[null]". The array of null is considered as an exception, I guess the exception causes the request becomes pending.

Related

Ext.Defer gives getAsynchronousLoad Error

I've just defined a combobox. Firstly it loads a countrylist and when select a value it's fire a change event which doing a ajax query to DB within searching service;
The thing; this configuration works pretty well when I click and open combobox items. But when I'm typing to combobox's field it's fires listener's store.load and because of none of country selected yet, the search query url gives not found errors of course.
{
xtype: 'countrycombo',
itemId: 'countryName',
name:'country',
afterLabelTextTpl: MyApp.Globals.required,
allowBlank: false,
flex: 1,
// forceSelection: false,
// typeAhead: true,
// typeAheadDelay: 50,
store: {
proxy: {
type: 'ajax',
// isSynchronous: true,
url: MyApp.Globals.getUrl() + '/country/list?limit=250',
// timeout: 300000,
reader: {
type: 'json',
rootProperty: 'data'
}
},
pageSize: 0,
sorters: 'description',
autoLoad: true
}
,
listeners: {
change: function (combo, countryId) {
var cityStore = Ext.getStore('cityCombo');
cityStore.getProxy()
.setUrl(MyAppp.Globals.getUrl() + '/city/view/search?query=countryid:'+ countryId);
// Ext.defer(cityStore.load, 100);
cityStore.load();
}
}
},
I've tried several things as you see in code above to set a delay/timeout for load during typing to combobox text field; Ext.defer, timeoutconfig on proxy, typeAhead config on combo but none of them worked!
I thought that Ext.defer is the best solution but it gives this error:
Uncaught TypeError: me.getAsynchronousLoad is not a function at load (ProxyStore.js?_dc=15169)
How can I set a delay/timeout to combobox to fires load function?
Instead of Ext.defer(cityStore.load, 100);
try using this :
Ext.defer(function(){
cityStore.load
}, 300);
If this doest work, try increasing your delay
or you can put a logic before loading
like this :
if(countryId.length == 5){
cityStore.load
}
This will ensure that you Entered the right values before loading
Hope this helps, and Goodluck on your project
well.. I've tried to implement #Leroy's advice but somehow Ext.defer did not fire cityStore.load. So I keep examine similar situations on google and found Ext.util.DelayedTask
So configured the listerens's change to this and it's works pretty well;
listeners: {
change: function (combo, countryId) {
var alert = new Ext.util.DelayedTask(function () {
Ext.Msg.alert('Info!', 'Please select a country');
});
var cityStore = Ext.getStore('cityCombo');
cityStore.getProxy().setUrl(MyApp.Globals.getUrl() + '/city/view/search?query=countryid:'+ countryId);
if (typeof countryId === 'number') {
cityStore.load();
} else {
alert.delay(8000);
}
}
}

CKEditor discards widget data after switching to source mode

I am developing a simple widget using the following code. Can anyone please explain to me why the attribute and text iv set turn to undefined after switching to "source mode"?
<pre>
/*
/dialogs/b2eupobject.js
*/
CKEDITOR.dialog.add( 'b2eupobject', function( editor ) {
return {
title: 'Edit Simple Box',
minWidth: 200,
minHeight: 100,
contents: [
{
id: 'info',
elements: [
{
id: 'objectId',
type: 'select',
label: 'ObjectName',
items: [ ['select', '-1' ],
['first name', '1' ],
['last name', '2' ],
],
setup: function( widget ) {
this.setValue( widget.data.title );
//this.setValue(widget.data.desc);
},
commit: function( widget ) {
widget.setData( 'title', this.getValue() );
var input = this.getInputElement().$;
widget.setData('desc',input.options[ input.selectedIndex ].text);
}
},
]
}
],
onShow: function() {
// The code that will be executed when a dialog window is loaded. This function will be defined above the onOk function
var selection = editor.getSelection(); //get to the element that is selected by the user (either highlighted or just having the caret inside)
var element = selection.getStartElement(); // get the element in which the selection starts
if ( element )
element = element.getAscendant( 'em', true ); // get the abbr element
console.log(this);
},
onOk: function() {
// The code that will be executed when a dialog window is loaded. This function will be defined above the onOk function
var selection = editor.getSelection(); //get to the element that is selected by the user (either highlighted or just having the caret inside)
var element = selection.getStartElement(); // get the element in which the selection starts
// if ( element )
console.log (element);
console.log(this);
}
};
} );
</pre>
<pre>
/*
plugin.js
*/
CKEDITOR.plugins.add( 'b2eupobject', {
requires: 'widget', //reference the generic Widget plugin that provides the Widget API
icons: 'b2eupobject',
init: function( editor ) {
CKEDITOR.dialog.add( 'b2eupobject', this.path + 'dialogs/b2eupobject.js' );
editor.widgets.add( 'b2eupobject', {
button: 'Insert user object',
template:'<em class="b2eUp">test </em>',
toolbar:'widgets',
parts: {elm: 'em.b2eUp'}, //this is a CSS selector of the element within the template above that you want to target
allowedContent: 'em ( b2eUp) [title]',
requiredContent : 'em(b2eUp) [title]',
dialog: 'b2eupobject',
init: function (widget) {
console.log("widget init : "+widget);
// widget.parts.elm.setAttribute('title',this.data.title);
// widget.parts.elm.setHtml(this.data.desc);
},
data: function (widget) {
this.parts.elm.setAttribute('title',this.data.title);
this.parts.elm.setHtml(this.data.desc);
},
upcast: function( element ) {
alert(element.name == 'em' && element.hasClass( 'b2eUp' ));
return element.name == 'em' && element.hasClass( 'b2eUp' );
},
} );
var pluginDirectory = this.path;
editor.addContentsCss( pluginDirectory + 'style/style.css' );
if ( editor.contextMenu ) {// check if contextmenu plugin exsists
editor.addMenuGroup( 'b2eupgrouGroup' ); // register a new menu group called abbrGroup.
editor.addMenuItem( 'b2eupItem', { //register a new menu item that will belong to the newly created group.
label: 'Edit user object',
icon: this.path + 'icons/b2eupobject.png',
command: 'b2eupobject',
group: 'b2eupgrouGroup'
});
editor.contextMenu.addListener( function( element ) { // add an event listener function that will be called whenever the context menu is fired.
if ( element.getAscendant( 'em', true ) ) {
// check if element is of type abbr
return { simpleboxitem: CKEDITOR.TRISTATE_OFF };
}
});
};
},
enter code here
} );
</pre>
I'm using CKEditor version 4.5 and I have both the widget and dialog plugins installed.
******* addition ******
when i return from source mode in the editor i can see that the upcast function is invoked.
writing to log, i can see that it returns true and that the element object :
FF console:
attributes: Object { class="b2eUp", title="1", data-cke-widget-data="%7B%7D", more...}
children:[Object { value="first name", _={...}, parent={...}, more...}]

bootstrap lightbox issues on launching a popup

i am using bootstrap light box as documented on http://www.jasonbutz.info/bootstrap-lightbox/
my html looks like below
<div id="demoLightbox" class="lightbox hide fade" tabindex="-1" role="dialog" aria-hidden="true">
<div class='lightbox-content'>
<img src="../images/details_close.png">
<div class="lightbox-caption"><p>Your caption here</p></div>
</div>
</div>
and js has a button onclick function as
function launchFlow(){
$('#demoLightbox').lightbox(true);
}
When i run the page and click the button in console i see the error:
Uncaught TypeError: Cannot read property 'offsetWidth' of undefined
plz advise how to fix it
entire js
$("#includedContent").load("navbar.html");
function launchFlow(){
$('#demoLightbox').lightbox(true);
}
function format ( d ) {
return '<b>Critical Path: </b>' +d.CriticalPath+' <input type=\"button\" class=\"btn btn-primary btn-primary\" value=\"View Execution Path\" onclick=\'launchFlow()\'/><br/><br/><b>Debug Trace: </b>' + d.DebugTrace
+ '<br/><br/><b>Stack Trace:</b> ' + d.MessageLong;
}
$(document).ready(function() {
var dt =$('#feedback-data-table').DataTable( {
ajax: {
url: "http://127.0.0.1:7101/MUDRESTService/rest/v1/feedbacks?limit=99",
dataSrc: "items"
},
columns: [
{
"class": "details-control",
"orderable": false,
"data": null,
"defaultContent": ""
},
{ title: "App Version", data: "AppVersion" },
{ title: "Feedback Type", data: "FeedbackType" },
{ title: "OS", data: "Os" },
{ title: "OS Version", data: "OsVersion" },
{ title: "Platform", data: "Platform" },
{ title: "Model", data: "Model" },
{ title: "User", data: "ReportedBy" },
{ title: "Date", data: "ReportedDate"},
{ title: "Server Url", data: "ServerUrl" }
]
} );
// Array to track the ids of the details displayed rows
var detailRows = [];
$('#feedback-data-table tbody').on( 'click', 'tr td.details-control', function () {
var tr = $(this).closest('tr');
var row = dt.row( tr );
var idx = $.inArray( tr.attr('FeedbackId'), detailRows );
if ( row.child.isShown() ) {
tr.removeClass( 'details' );
row.child.hide();
// Remove from the 'open' array
detailRows.splice( idx, 1 );
}
else {
tr.addClass( 'details' );
$.ajax({ url: 'http://127.0.0.1:7101/MUDRESTService/rest/v1/feedbacks/' +
415 + '/child/MudFeedbackDetailsVO?onlyData=true',
type: 'get',
dataType: 'json',
success: function(output) {
 console.log(output.items[0].CriticalPath) ;
results = output.items[0];
}
}).done(function(output){
row.child( format( output.items[0] ) ).show();
});
// Add to the 'open' array
if ( idx === -1 ) {
detailRows.push( tr.attr('FeedbackId') );
}
}
} );
// On each draw, loop over the `detailRows` array and show any child rows
dt.on( 'draw', function () {
$.each( detailRows, function ( i, id ) {
$('#'+id+' td.details-control').trigger( 'click' );
} );
} );
} );
Any JavaScript (including functions) that use jQuery should be within your $(document).ready(function() {. Also, your $('#demoLightbox').lightbox(true); statement never runs, unless you call the function it is wrapped in someplace else.
The $('#demoLightbox').lightbox(true); statement should be within the $(document).ready(function() { and does not need to be wrapped in a function unless you need to bind the lightbox functionality to the same element at another time.
For example:
$(document).ready(function() {
$('#demoLightbox').lightbox(true);
...

Multiple Initialization After Destruction

I have a function that creates an instance of DataTables and for some reason it initializes n-times after destruction. I only noticed this because I add custom fields on init and they were multiplying. I could prevent that but that only deals with the symptom.
To clarify, after I "destroy: the instance and reinitialize it, to change the data source, if it's the second time it initializes twice. Three times if it's the 3rd time, etc.
I speculate that the table variable is part of the closure formed by the function because even if I set table = null the same thing happens.
How can I prevent this?
DataTables Function
/*Create a DataTable on tableElementID using pageUrl as the source*/
function ajaxLoadTable ( pageUrl, tableElementID ) {
window.table = $(tableElementID)
.on( 'init.dt', function () {
//The success function is used internally so it should NOT be overwritten, have to listen for this event instead
//Add our custom fields _length refers to an element generated datatables
if ( additionalElements.saveButton ) {
$(tableElementID + '_length').after('<div class="dataTables_filter"><button>Save All Edits</button></div>');
}
if ( additionalElements.selectState ) {
$(tableElementID + '_length').after('<div class="dataTables_filter"><label>Project State: <select name="projectState" style="width:auto;"><option>Select ...</option><option value="Active">Active</option><option value="Historical">Historical</option></select></label></div>');
}
if ( additionalElements.searchBox ) {
$(tableElementID + '_length').after('<div class="dataTables_filter"><label>Search:<input type="search" id="customSearch" style="width:auto;"></label></div>');
}
})
.DataTable({
"processing": true,
"serverSide": true,
"ajax":{
type: "POST",
url: pageUrl,
data: function ( additionalData ) {
$('.serverData').each( function( index, element ){
if( element.nodeName === "SELECT"){
additionalData[element.name.toUpperCase()] = element.options[element.selectedIndex].value;
return true; //return true is equivalent to continue for $.each
}
additionalData[element.name.toUpperCase()] = element.value;
});
},
dataType: "json"
},
"pageLength": 4,
"lengthMenu": [ 4, 8, 12, 16, 24 ],
"searchDelay": 1500,
"columnDefs":
{ "targets": 0,
"orderable": false,
"data": {
"_": "display"
}
}
});
}
Destruction Function
/*Load the selected project state*/
$('html').on( 'change' , '[name=projectState]' ,function(){
var currentState = $('option:selected', this).val();
$('#projectState').val(currentState);
//Remove the old table records and the datatables. Order matters, otherwise there is unsual behavior.
if( $.fn.DataTable.isDataTable( '#searchTable' ) ) {
window.table.destroy();
window.table = null;
}
$('.projectStateText').html( currentState );
//Get the new table records
ajaxLoadTable( *some undisclosed URL*, '#searchTable');
});

How do I stop ext-js from adding limit=25 to my JSON query?

The following code is working. The problem is the request is being sent with &_dc=1299207914646&limit=25 appended to every request sent to the server. Nothing I can do changes the limit=25. Ideally I want no additional parameters sent to the server. I would make do however with being able to set the limit to 10000 or something. I AM able to add other parameters but nothing I do removes the limit=25. I would also like to get rid of the &_dc parameter although I don't know why it has been added it is not causing a problem.
Any ideas?
note: some weird problem with code formatting below?
Thanks
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.panel.*'
]);
Ext.onReady(function(){
Ext.regModel('Image_', { // window.Image is protected in ie6 !!!
fields: ['id', 'key', 'value']
});
var store = new Ext.data.JsonStore({
model: 'Image_',
proxy: {
type: 'ajax',
var store = new Ext.data.JsonStore({
model: 'Image_',
proxy: {
type: 'ajax',
autoload: 'false',
url: '/couchdb/test/_design/blah/_view/by_surname2?startkey=%22r%22&endkey=%22r\u9999%22',
reader: {
type: 'json',
root: 'rows'
}
}
});
store.load();
var listView = new Ext.grid.GridPanel({
width:425,
height:250,
collapsible:true,
title:'Simple ListView <i>(0 items selected)</i>',
renderTo: Ext.getBody(),
store: store,
multiSelect: true,
viewConfig: {
emptyText: 'No images to display'
},
headers: [{
text: 'File',
flex: 50,
dataIndex: 'value'
},{
text: 'Last Modified',
flex: 35,
dataIndex: 'key'
},{
text: 'Size',
dataIndex: 'id',
flex: 15,
cls: 'listview-filesize'
}]
});
// little bit of feedback
listView.on('selectionchange', function(view, nodes){
var l = nodes.length;
var s = l != 1 ? 's' : '';
listView.setTitle('Simple ListView <i>('+l+' item'+s+' selected)</i>');
});
});
In your Proxy, set
limitParam: undefined,
pageParam: undefined,
startParam: undefined,
noCache: false,
You can modify your store limit when you load the store.
store.load({params:{limit:50}});
In this case, I am asking to set the limit to 50.
_dc=1299207914646 is unique cache-buster param added to GET requests. If you don't want to have them in the url, you can disable them by setting disableCaching parameter to false.
But I would recommend you to set the method of you store to POST and pass the parameters using POST rather than GET method. That way you can have clean URLs and also hide the data being sent.
You can override getParams method of the Ext.data.proxy.Server.
For example, in my project I added custom boolean parameter embeddedParams and if I dont want to add ExtJS parameters to a request I set it to false in a store proxy:
/**
* Added embeddedParams option
*/
Ext.define('Ext.lib.overrides.ServerProxy', {
override: 'Ext.data.proxy.Server',
/**
* Add or not pagination, grouping, sorting and filtering parameters to the request. Defaults to true.
*/
embeddedParams: true,
/**
* #private
* Copy any sorters, filters etc into the params so they can be sent over the wire
*/
getParams: function (operation) {
var me = this,
params = {},
isDef = Ext.isDefined,
groupers = operation.groupers,
sorters = operation.sorters,
filters = operation.filters,
page = operation.page,
start = operation.start,
limit = operation.limit,
simpleSortMode = me.simpleSortMode,
simpleGroupMode = me.simpleGroupMode,
pageParam = me.pageParam,
startParam = me.startParam,
limitParam = me.limitParam,
groupParam = me.groupParam,
groupDirectionParam = me.groupDirectionParam,
sortParam = me.sortParam,
filterParam = me.filterParam,
directionParam = me.directionParam,
hasGroups, index;
if (me.embeddedParams && pageParam && isDef(page)) {
params[pageParam] = page;
}
if (me.embeddedParams && startParam && isDef(start)) {
params[startParam] = start;
}
if (me.embeddedParams && limitParam && isDef(limit)) {
params[limitParam] = limit;
}
hasGroups = me.embeddedParams && groupParam && groupers && groupers.length > 0;
if (hasGroups) {
// Grouper is a subclass of sorter, so we can just use the sorter method
if (simpleGroupMode) {
params[groupParam] = groupers[0].property;
params[groupDirectionParam] = groupers[0].direction || 'ASC';
} else {
params[groupParam] = me.encodeSorters(groupers);
}
}
if (me.embeddedParams && sortParam && sorters && sorters.length > 0) {
if (simpleSortMode) {
index = 0;
// Group will be included in sorters, so grab the next one
if (sorters.length > 1 && hasGroups) {
index = 1;
}
params[sortParam] = sorters[index].property;
params[directionParam] = sorters[index].direction;
} else {
params[sortParam] = me.encodeSorters(sorters);
}
}
if (me.embeddedParams && filterParam && filters && filters.length > 0) {
params[filterParam] = me.encodeFilters(filters);
}
return params;
}
});
Usage:
store: Ext.create('Ext.data.Store', {
...
proxy: {
...
type: 'ajax', // or 'direct', 'jsonp' / 'scripttag'
embeddedParams: false
}
})
add the limit property to your store...
limit:50,
and might not hurt to try pagesize....
pagesize:50
and see if either of these help.
Edit : also try
pageParam:undefined,
in your proxy.
found that last piece from...
http://www.sencha.com/forum/showthread.php?118445-CLOSED-1.0.1-Ext.data.JsonStore-quot-limit-quot-param-issue
You can modify the limit param using
store.proxy.limitParam=null;
To remove the _dc parameter on extjs 4 you can set:
noCache: false
or just uncheck the box if you're using architect 2.
Specifically for Json, to get rid of _dc parameter, in your proxy object, set the config option given by Tharahan:
proxy: {
type: 'ajax',
api: {
read: 'app/data/something.json',
update: 'app/data/something.json'
},
reader: {
type: 'json',
...
},
writer: {
type: 'json',
...
},
noCache: false
}
EDIT: (sorry, I did not look at the post date, but lost so much time with it) Please note that the global Ext.Loader.setConfig({disableCaching: false}); does not affect subclasses of Ext.data.proxy.Server which need this specific option (at least in development with sencha touch 2.2.0).

Categories