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);
}
Related
I have got to know toaster.js from this site and trying to implement it in my web app. I have done it according to the example but it doesn't work.
Here is my service where I Implemented:
function () {
angular
.module('FoursquareApp')
.factory('DataService', DataService);
DataService.$inject = ['$http','toaster'];
function DataService($http, toaster) {
.id,
venueName: venue.name,var serviceBase = '/api/places/';
var placesDataFactory = {};
var userInContext = null;
var _getUserInCtx = function () {
return userInContext;
};
var _setUserInCtx = function (userInCtx) {
userInContext = userInCtx;
};
var _savePlace = function (venue) {
//process venue to take needed properties
var minVenue = {
userName: userInContext,
venueID: venue
address: venue.location.address,
category: venue.categories[0].shortName,
rating: venue.rating
};
return $http.post(serviceBase, minVenue).then(
function (results) {
toaster.pop('success', "Bookmarked Successfully", "Place saved to your bookmark!");
},
function (results) {
if (results.status == 304) {
toaster.pop('note', "Faield to Bookmark", "Something went wrong while saving :-(");
}
else {
toaster.pop('error', "Failed to Bookmark", "Something went wrong while saving :-(");
}
return results;
});
};
I have called the library scripts in index.html and also the css files.
Any ideas of what I might be doing wrong?
Are you sure that you use toaster.js library? The popular one is toastr.js
Try to modify your code to
DataService.$inject = ['$http','toastr'];
function DataService($http, toastr) {
...
Also ensure, that you link this js file in you index.html and also refer this package in main app module definition as a second (dependency) parameter
When I run navAction-test.js below I get following error: TypeError: Cannot read property 'DATA_LOADED' of undefined
As I understand it the constant.DATA_LOADED is undefined, I'm guessing jest is mocking it and for this reason constant is undefined, I've tried everything I could find on the next but it remains undefined.
Is there anyone out there who can help. I would really appreciate it.
navAction.js:
var dispatcher = require('../dispatcher/AppDispatcher');
var constants = require('../constants/constants');
module.exports = {
load: function() {
def = $.ajax({
url: 'http://api.facebook.com/',
data: {},
success: function (data, textStatus, jqXHR) {
dispatcher.dispatch({type: constants.DATA_LOADED, data: data});
}
});
}
}
navAction-test.js:
jest.dontMock('../navAction.js');
describe('Tests NavigationCollectionActionCreators', function() {
var $;
var dispatcher;
var navAction;
beforeEach(function() {
$ = require('jquery');
dispatcher = require('../../dispatcher/AppDispatcher');
navAction = require('../navAction.js');
});
it('tests calls $.ajax & dispatcher ', function () {
navAction.load();
$.ajax.mock.calls[0][0].success({body: {header: {items: [{name: 'The name', link: 'http://www.facebook.com'}]}}});
expect(dispatcher.dispatch).toBeCalledWith({type: 'DATA_LOADED', data: [{name: 'The name', link: 'http://www.timeout.com'}]});
});
});
//constants.js
var keyMirror = require('keymirror');
module.exports = keyMirror({
DATA_LOADED: null,
});
UPDATE:
I got this to work by adding the following to navAction-test.js:
var constants = {
DATA_LOADED: 'DATA_LOADED',
DATA_NOT_LOADED: 'DATA_NOT_LOADED'
};
jest.setMock('../../constants/constants', constants);
Is this the correct way of doing it?
Add to test:
jest.dontMock('../constants/constants');
If you do not want to use automocking at all, you can remove all of the jest.dontMock and put instead:
jest.autoMockOff();
Your method to solve the problem (in the update at the bottom) is not appropriate in my opinion because it violates DRY (do not repeat yourself). What happens when you added another action constant? Now you have to remember to add it in the test too. That is problematic.
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 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();