i did a custom plugin to add common functionality and validations to jQuery File Upload plugin. This is a resume so you can get the idea.
$.fn.myCustomUpload = function(options) {
if (!$(this).is('input:file')) {
return false;
}
$(this).fileupload({
maxChunkSize: options.maxChunkSize,
maxFileSize: options.maxFileSize,
acceptFileTypes: options.allowedTypes,
type: 'POST',
dataType: 'json',
add: function (e, data) {
// common validations
},
start: function (e) {
// foo
if (options.onUploadStart) {
options.onUploadStart();
}
},
fail: function(e, data) {
// foo
if (options.onUploadError) {
options.onUploadError(result);
}
},
done: function(e, data) {
// foo
if (options.onUploadDone) {
options.onUploadDone(media_data);
}
}
});
};
The thing is that I made validations or process data, and return the results with callbacks. But, I notice that the callbacks were override with the next call to the plugin.. So, I upload a file in one place, and re the result show in another! What i'm doing wrong?
Should I need to store the options to each input element, like .data()?
EDIT 2: Fiddle of the html, and JS structure (not functional)
https://jsfiddle.net/a6axfm3v/
EDIT: I use this plugin in two ways
$input.myCustomUpload({
// ...
onUploadStart: this.onNewPostUploadStart.bind(this),
onUploadProgress: this.onNewPostUploadProgress.bind(this), //this reference to my object
onUploadError: this.onNewPostUploadError.bind(this),
// ...
});
$uploads_buttons = $container.find('._attach_image');
$uploads_buttons.each(function() {
var $upload_button = $(this);
var $parent = $upload_button.parents('._post-container');
$upload_button.myCustomUpload({ /*options, callbacks, etc*/});
});
$input has their own callbacks, and $uploads_buttons all have the same, but different that the $input ones..
Thanks.
Related
i am trying to make put my app in production mode , i face problem that my js code keep complain about missing javascript object and not run ,
in my app.js i have this
requires: [
"FleetM.utility.SharedData"
],
and this shared data is used in all controllers and view as singleton with name SharedData , but after build , the minified js keep say that SharedData is missing , but if i put it in console it print all values, even if i use uncompressed js the same result , here is my SharedData class
Ext.define('FleetM.utility.SharedData', {
alternateClassName: 'SharedData',
singleton: true,
'PreventALLUpdateDelete': 0,
'vehicles_creation': 0,
//..... alot of varibles here
'appSettings': 0,
'user': 0,
'i18n': 0,
success_load: false,
'comWizard': 0,
constructor: function () {
Ext.Ajax.request({
url: "USERS/GetAccessLevelData",
method: 'GET',
scope: this,
success: function (response, opts) {
var data = Ext.decode(response.responseText, true);
try {
SharedData.user = data;
SharedData.user.Connected=1;
} catch (err) {
}
try {
SharedData.PreventALLUpdateDelete = data.PreventALLUpdateDelete;
SharedData.vehicles_creation = data.vehicles_creation;
var language = SharedData.user.language;
} catch (err) {
}
switch (language) {
case '0':
language = "En";
break;
case '1':
language = "Ar";
break;
default:
language = "En";
break;
}
this.LoadI18n(language);
success_load: true;
},
failure: function (err) {
//Ext.MessageBox.alert(SharedData.i18n.Reports.ErrorMsg, SharedData.i18n.Reports.tryAgain);
}
});
},
LoadI18n: function (language) {
var me = this;
Ext.Ajax.request({
url: "data/i18n" + language + ".json",
method: 'GET',
scope: this,
success: function (response, opts) {
var data = Ext.decode(response.responseText, true);
try {
SharedData.i18n = data;
} catch (err) {
}
me.success_load = true;
},
failure: function (err) {
//Ext.MessageBox.alert(SharedData.i18n.Reports.ErrorMsg, SharedData.i18n.Reports.tryAgain);
}
});
}
});
----UPDATE----
I have done add requires for all controllers , and views , it still
complain
look at the images bellow ,
You have to add it to the requires array of each class, to have it available for all of it.
It is not enough to have it just in your app.js.
In development mode the missing class can be loaded dynamically, but in the production app.js all requires are appended in the order they need to be.
For Example: requires["C1", "FleetM.utility.SharedData", "C2"]
Would result in an app.js like
All the code with the requires for C1
All the code and requires for SharedData
All the code and requires for C2
When C1 needs SharedData for it's functionality it has to require it as well or SharedData is not available at that time for C1.
Update
You can not access the singleton FleetM.utility.SharedData during the configuration of the class, because it is not initialized during that point.
You should be able to access it in the constructor method of the store.
constructor: function() {
this.data = [
id: 0,
name: SharedData.i18n.configuration.Type_Vehicles
];
this.callParent(arguments);
}
I tried to sync database return html string append to each .buttonContainer , use action.js execute other file loadButton module use parameter point specific element.
the result should be use different .buttonContainer and with their attr id connect db get result append to each .buttonContainer
My question is if I set ajax option async default true, then both return html string will append to the last .buttonContainer.
I can't understand I already set each module/function have their attr el from each execute parameter.
Why and how to solve it?
I tried to change async to false then it work but slowly the page, so I'm trying to find other solution.
<div class="buttonContainer" data-user-id="0"></div>
<div class="buttonContainer" data-user-id="1"></div>
action.js
define(['DomReady!', 'jquery', 'loadButton'],function (DomReady, $, loadButton) {
return {
init: function() {
// loop each element as parameter and execute
$('.buttonContainer').each(function(index, el) {
var config = {};
config.el = $(this);
loadButton.init(config);
});
},
}
});
loadButton.js
define(['DomReady!', 'jquery'],function (DomReady, $) {
return {
init: function(config) {
this.config = {};
this.config.el = config.el; // set each execute have their own private attribute
this.onLoadAction();
},
onLoadAction: function() {
this.onLoadController();
},
onLoadController: function() {
var userId = this.config.el.attr('data-user-id');
var mthis = this;
this.onLoadRequestDB('load/'+userId).done(function(response) {
console.log(mthis.config.el);
var response = JSON.parse(response);
mthis.config.el.append(response.button);
});
},
onLoadRequestDB: function(url) {
return $.ajax({
url: url,
type: 'GET',
processData: false,
contentType: false,
// async: false
});
},
}
});
Edit:
https://stackoverflow.com/a/22121078/1775888 I found some solution here, so I edit loadButton.js like this
..
init: function(config) {
this.config = {};
this.config.el = config.el; // set each execute have their own private attribute
this.onLoadAction(this.config);
},
onLoadAction: function(config) {
this.onLoadController(config);
},
onLoadController: function(config) {
..
pass parameter, then it work.
But I still want to know why I set the loadButton.js init this, in each loop but still can be cover after ajax. makes all response append to element from last execute loadButton.js config parameter
I'm using Angular with ngResource and i've got an api url:
GET http://my.com/rest/items?inState=TRANSIENT&inState=FINAL
How could I do query with two (not uniq) params 'inState'?
This is my Resource factory:
.factory('Resource', function ($resource, REST_URL) {
return {
items: $resource(REST_URL + 'rest/items',
{},
{
get: {method: "GET", params: {inState: '#inState'}}
})
};
})
And this is the way I'm call it:
//GET http://my.com/rest/items?inState=TRANSIENT
Resource.items.get({inState: 'TRANSIENT'}, function (data) {
//...
}, function (responce) {
//...
});
This is works but the problem is in how I'm send params - as object: {inState: 'TRANSIENT'}
I cannot write something like
{inState: 'TRANSIENT', inState: 'FINAL'}
beacuse of fields must be uniq
P.S. I know that it may be done with $http.
That's how to do this:
{inState: ['TRANSIENT', 'FINAL']
Example:
//GET http://my.com/rest/items?inState=TRANSIENT&inState=FINAL
Resource.items.getHistory({inState: ['TRANSIENT', 'FINAL']}, function (data) {
//...
}, function (responce) {
//...
});
Not sure if you have control over what is consuming the parameters, but if you do you could try passing the parameters as an object with an array of objects in it, like this:
{ states : [{inState : 'TRANSIENT'}, {inState : 'FINAL'}]}
Then just iterate through the states array and check each inState property.
i was just wondering if getting a jqgrid event from a main javascript and separate it using another javascript in a form of function would work? what im trying to do is like this. i have a code :
...//some code here
serializeGridData: function(postData) {
var jsonParams = {
'SessionID': $('#eSessionID3').val(),
'dataType': 'data',
'recordLimit': postData.rows,
'recordOffset': postData.rows * (postData.page - 1),
'rowDataAsObjects': false,
'queryRowCount': true,
'sort_fields': postData.sidx
};
if (postData.sord == 'desc')
{
...//some code here
}
else
{
...//some code here
}
return 'json=' + jsonParams;
},
loadError: function(xhr, msg, e) {
showMessage('errmsg');
},
...//some code here
i want to get this code and write this in another javascript file and make this as a function, so that my other file could use this one..is it possible?
i created something like this in my other javascrtip file where i planned to put all my functions. here's the code (functions.js):
function serialLoad(){
serializeGridData: function(postData) {
var jsonParams = {
'SessionID': $('#eSessionID3').val(),
'dataType': 'data',
'recordLimit': postData.rows,
'recordOffset': postData.rows * (postData.page - 1),
'rowDataAsObjects': false,
'queryRowCount': true,
'sort_fields': postData.sidx
};
if (postData.sord == 'desc')
{
...//some code here
}
else
{
...//some code here
}
return 'json=' + jsonParams;
},
loadError: function(xhr, msg, e) {
showMessage('errmsg');
}
}
this isn't working and display a message syntax error. i don't know how to correct this. is there anyone who can help me.?
First of all the answer on your derect question. If you define in the functions.js file some global variable, for example, myGlobal:
myGlobal = {};
myGlobal = serializeGridData: function(postData) {
// ... here is the implementation
};
you can use it in another JavaScript file which must be included after the functions.js file:
serializeGridData: myGlobal.serializeGridData
(just use such parameter in the jqGrid definition).
If you want to use the serializeGridData parameter with the value in the most of your jqGrids you can overwrite the default value of serializeGridData in the functions.js file instead:
jQuery.extend(jQuery.jgrid.defaults, {
datatype: 'json',
serializeGridData: function(postData) {
// ... here is the implementation
},
loadError: function(xhr, msg, e) {
showMessage('errmsg');
}
});
In the example I ovewride additionally default datatype: 'xml' jqGrid parameter to datatype: 'json'. It shows that in the way you can set default values of any jqGrid parameter.
What it seems to me you really need is to use prmNames jqGrid parameter to rename some defaulf names of the standard jqGrid parameters. For example with
prmNames: {
rows:"recordLimit",
sort: "sort_fields",
search:null,
nd:null
}
you rename the standard rows parameter to recordLimit, the sidx to sort_fields and remove _search and nd parameters to be send.
Additionally you can use postData having some properties defined as the function (see here for details). For example:
postData: {
SessionID: function() {
return $('#eSessionID3').val();
},
rowDataAsObjects: false,
queryRowCount: true,
dataType: 'data',
recordOffset: function() {
var pd = jQuery("#list2")[0].p.postData;
return pd.recordLimit * (pd.page - 1);
},
json: function() {
var pd = jQuery("#list2")[0].p.postData;
return {
SessionID: $('#eSessionID3').val(),
dataType: 'data',
recordOffset: pd.recordLimit * (pd.page - 1),
rowDataAsObjects: false,
queryRowCount: true,
sort_fields: pd.sort_fields
};
}
}
I used here both json parameter which you currently use and add parameters like SessionID, queryRowCount and so on directly in the list of parameters which will be send. Of course it is enough to send only one way (either json or the rest) to send the aditional information which you need.
The second example is incorrect, as you are declaring a javascript object as the body of a function, what you could do is:
function serialLoad() {
// Return an object with the required members
return {
serializeGridData: function(postData) { ... },
loadError: function(xhr, msg, e) { ... }
};
}
You are mixing function declaration and object literal notation. This syntax: property: value is used when creating an object with object literal notation:
var obj = {
prop: val,
prop2: val
};
serializeGridData and loadError are properties of some object and you cannot define those by just putting them into a function.
One way would be to create two functions, one for serializeGridData and one for loadError, e.g.
function serialLoad(postData){
var jsonParams = {
//...
};
if (postData.sord == 'desc') {
//... some code here
}
else {
//... some code here
}
return 'json=' + jsonParams;
}
function onError(xhr, msg, e) {
showMessage('errmsg');
}
Then you can assign them in your other file to the object:
// ... some code here
serializeGridData: serialLoad,
loadError: onError,
//... some code here
Another way is to pass the object in question to the function and assign the properties there:
function attachLoadHandler(obj) {
obj.serializeGridData = function(postData) {
//...
};
obj.loadError = function(xhr, msg, e) {
//...
};
}
Then you have to pass the object you created to that function:
attachLoadHandler(obj);
But I think the first approach is easier to understand.
I'm about to make a web app which will have a pretty heavy client end. I'm not sure about the way to organize my javascript code, but here is a basic idea :
// the namespace for the application
var app = {};
// ajax middle layer
app.products = {
add : function(){
// send ajax request
// if response is successful
// do some ui manipulation
app.ui.products.add( json.data );
},
remove : function(){},
...
};
app.categories = {
add : function(){},
....
};
// the ui interface which will be called based on ajax responses
app.ui = {};
app.ui.products = {
add : function( product_obj ){
$('#products').append( "<div id='"+product_obj.id+"'>"+product_obj.title+"</div>" );
}
};
app.ui.categories = {};
Anybody got similar experiences to tell me the pros and cons of this approach? What's your way of designing client side javascript code architecture? Thanks.
[update] : This web app, as you see from the above, deals with products CRUD, categories CRUD only in a ajax fashion. I'm only showing an snippet here, so you guys know what I'm trying to achieve and what my question is. Again, I'm asking for inputs for my approach to organize the code of this app.
That is similar to the way I do my JavaScript projects. Here are some tricks I have used:
Create one file for each singleton object. In your code, store ajax, middle layer and ui interface in separate files
Create a global singleton object for the 3 layers usually in the project; GUI, Backend and App
Never use pure ajax from anywhere outside the Backend object. Store the URL to the serverside page in the Backend object and create one function that uses that URL to contact the server.
Have a JSON class on the server that can report errors and exceptions to the client. In the Backend object, check if the returned JSON object contains an error, and call the serverError function in the GUI class to present the error to the user (or developer).
Here is an example of a Backend object:
var Backend = {};
Backend.url = "/ajax/myApp.php";
Backend.postJSON = function(data, callback){
var json = JSON.stringify(data);
$.ajax({
type: "POST",
url: Backend.url,
data: "json="+json,
dataType: "json",
success: function(response){
if(response){
if(response.task){
return callback(response);
}else if(response.error){
return Backend.error(response);
}
}
return Backend.error(response);
},
error: function(response){
Backend.error({error:"network error", message:response.responseText});
},
});
};
Backend.error = function(error){
if(error.message){
Client.showError(error.message, error.file, error.line, error.trace);
}
};
This can be improved by storing the ajax object somewher in the Backend object, but it's not necessary.
When you build something non trivial, encapsulation is important to make things maintainable in long run. For example, JS UI is not just simple JS methods. A UI components consists of css, template, logic, localization, assets(images, etc).
It is same for a product module, it may need its own settings, event bus, routing. It is important to do some basic architectural code in integrating your chosen set of libraries. This had been a challenge for me when I started large scale JS development. I compiled some best practices in to a reference architecture at http://boilerplatejs.org for someone to use the experience I gained.
For client-side ajax handling I have a URL object that contains all my urls and than I have an ajax object that handles the ajax. This is not a centric approach.In my case I have I have different urls handling different tasks. I also pass a callback function to be executed into the ajax object as well.
var controller_wrapper = {
controller: {
domain: "MYDOMAIN.com",
assets: "/assets",
prefix: "",
api: {
domainer: "http://domai.nr/api/json/info",
tk_check: "https://api.domainshare.tk/availability_check"
},
"perpage": "/listings/ajax",
"save_image": "/members/saveImage",
"update": "/members/update",
"check_domain": "/registrar/domaincheck",
"add_domain": "/registrar/domainadd",
"delete_listing": "/members/deactivateProfile",
"save_listing": "/members/saveProfile",
"get_images": "/images/get",
"delete_image": "/images/delete",
"load_listing": "/members/getProfile",
"load_listings": "/members/getListings",
"loggedin": "/members/loggedin",
"login": "/members/login",
"add_listing": "/members/add",
"remove": "/members/remove",
"get": "/members/get",
"add_comment": "/members/addComment",
"load_status": "/api/loadStatus"
}
}
var common = {
pager: 1,
page: 0,
data: {
saved: {},
save: function (k, v) {
this.saved[k] = v;
}
},
ajax: {
callback: '',
type: 'POST',
url: '',
dataType: '',
data: {},
add: function (k, val) {
this.data[k] = val;
},
clear: function () {
this.data = {};
},
send: function () {
var ret;
$.ajax({
type: this.type,
url: this.url,
data: this.data,
dataType: this.dataType !== '' ? this.dataType : "json",
success: function (msg) {
if (common.ajax.callback !== '') {
ret = msg;
common.ajax.callback(ret);
} else {
ret = msg;
return ret;
}
return;
},
error: function (response) {
console.log(response);
alert("Error");
}
})
}
}
var callback = function (results) {
console.log(results
}
common.ajax.callback = callback;
common.ajax.type = "jsonp";
common.ajax.type = "POST";
common.ajax.url = controller_wrapper.controller.perpage;
common.ajax.add("offset", common.page);
common.ajax.add("type", $("select[name='query[type]']").val());
common.ajax.add("max", $("select[name='query[max]']").val());
common.ajax.add("min", $("select[name='query[min]']").val());
common.ajax.add("bedrooms", $("select[name='query[bedrooms]']").val());
common.ajax.add("sort", $("select[name='query[sort]']").val());
common.ajax.send();