I have a function with if inside. In case if returns false I need repeat function again
this.reloadComment = function () {
var previous_comment = self.Comment();
$.getJSON(Routes.my_service_search_path(self.ID), {}, function (data) {
if (data.Comment.ID != previous_comment.ID) {
self.Comment(data.Comment);
} else {
// repeat
}
});
};
If self within the function is what this is outside it, then simply:
} else {
// repeat
self.reloadComment();
}
If not, use a named function; then since you have that nice name you can use, call it when you need to repeat it:
function reloadComment() {
var previous_comment = self.Comment();
$.getJSON(Routes.my_service_search_path(self.ID), {}, function (data) {
if (data.Comment.ID != previous_comment.ID) {
self.Comment(data.Comment);
} else {
// repeat
reloadComment();
}
});
}
this.reloadComment = reloadComment;
If you don't need to support IE8, you can do that with a single named function expression:
this.reloadComment = function reloadComment() {
var previous_comment = self.Comment();
$.getJSON(Routes.my_service_search_path(self.ID), {}, function (data) {
if (data.Comment.ID != previous_comment.ID) {
self.Comment(data.Comment);
} else {
// repeat
reloadComment();
}
});
};
...but on IE8 (and earlier) you'd end up with two copies of that function, not one; if you do that a lot, it ends up being wasteful. (It wouldn't make any other difference in this particular case, though; it'd still work. There are other situations where it would make a difference, so I stay away from NFEs entirely in code that needs to deal with IE8.)
Try This
this.reloadComment = function () {
var me = this;
var previous_comment = self.Comment();
$.getJSON(Routes.my_service_search_path(self.ID), {}, function (data) {
if (data.Comment.ID != previous_comment.ID) {
self.Comment(data.Comment);
} else {
me.reloadComment();
}
});
};
Related
I keep finding myself in these loops where I'm working through user input to make sure I'm getting what's expected. However, I don't know how to do this without calling a function before it is defined, which gives me eslint error: no-use-before-define.
function tryAgain(){
alertBadInput();
getInput();
}
function getInput(){
var input = askForInput();
if (input === 'bad') {
tryAgain();
return;
}
processInput(input);
}
No matter what order I define these two functions, one of them will be calling another before it is defined.
It seems syntactically valid, but given the eslint error, what other pattern can I use if I were hoping to avoid that error?
Although it might be ok for two functions to call each other, you might be better of using a while loop for clarity (and that's what it's for) and to comply with the coding standard avoiding the error altogether, like so:
function getInput() {
var no_valid_input = true;
var input = null;
while (no_valid_input) {
input = askForInput();
if (input !== 'bad') {
no_valid_input = false;
} else {
alertBadInput();
}
}
processInput();
}
Working example:
function processInput() {
return alert('Yep, processing...');
}
function alertBadInput() {
return alert('Nope');
}
function askForInput() {
return prompt('What?');
}
function getInput() {
var no_valid_input = true;
var input = null;
while (no_valid_input) {
input = askForInput();
if (input !== 'bad') {
no_valid_input = false;
} else {
alertBadInput();
}
}
processInput();
}
getInput();
Disabling the error
Although it doesn't really solve the problem, it may make sense to disable it for a specific use-case.
// eslint-disable-next-line no-use-before-define
Use it like this:
function tryAgain(){
alertBadInput();
// eslint-disable-next-line no-use-before-define
getInput();
}
function getInput(){
var input = askForInput();
if (input === 'bad') {
tryAgain();
return;
}
processInput(input);
}
Use-case
I've had to use this in a module with a class where I did not want to expose my class-specific function (with similar format to the following code). Flipping the class and function around yields the same eslint error.
It'll either be:
prepare before Request where Request is used by prepare, or
Request before prepare where prepare is used by Request.
This is obviously a simplification, but gives you the general idea:
// function that I don't export
function prepare(request) {
// eslint-disable-next-line no-use-before-define
if (request instanceof Request) {
return JSON.stringify(request.obj)
} else {
return new TypeError('Wrong type given, expected Request')
}
}
// class that export that uses the prepare function
class Request{
constructor() {
this.obj = {}
}
doSomething() {
const request = prepare(this)
// do something with request
}
addX(x) {
this.obj.x = x
}
}
module.exports = Request
I have JavaScript class which have huge functions which are very difficult to maintain.
The 2 public functions are called at start and then on click. I want to create private functions inside these public functions say break into into some private functions scope to these public methods.
var searchResultView;
var SearchResultView = function () {
me = this;
this.init = function () {
// huge code
}
this.Search = function () {
// huge code
}
}
jQuery(function () {
searchResultView = new SearchResultView();
searchResultView.init();
searchResultView.Search();
}
What will best way to achieve this. I tried to use below approach but i think this nested function will not work well.
var searchResultView;
function searchResultView() {
me = this;
this.init = function () {
var declareControls = function () {}
var addEvents = function () {}
var fillControls = function () {}
declareControls();
addEvents();
fillControls();
}
this.Search = function () {
var validateAndCreateCriteria = function () {
if (!validateAandGetLocation()) {
alert("invalid location");
return false;
}
if (!validateAandGetCategory()) {
alert("choose search type");
return false;
}
var validateAandGetLocation = function () {}
var validateAandGetCategory = function () {}
}
validateAndCreateCriteria();
}
}
jQuery(function () {
searchResultView = new searchResultView();
searchResultView.init();
});
If I understood correctly, you should have the functions something like this:
var foo = (function() {
var privateBar = function() { // private function
},
privatefooBar = function() { // private function
};
return {
publicFoo : function() { //public function
/* use privateBar and privatefooBar functions here */
}
};
})();
Later you can access publicFoo function by using
foo.publicFoo();
But you can't access the inside functions which are privateBar() and privatefooBar() directly because they are private functions.
Updated Fiddle
Breaking up the function is easy:
function f(..) {
// many lines here
return ret_f;
}
if equivalent to
function f {
function f1(..) {
// not so many lines here
}
function f2(..) {
// not so many lines here
}
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
or if you prefer this style using anonymous functions
function f {
var f1 = function(..) {
// not so many lines here
};
var f2 = function(..) {
// not so many lines here
};
var ret_f1 = f1(..);
var ret_f2 = f2(..);
// calculate ret_f from ret_f1 and ret_f2
return ret_f;
}
I fear however your real question is specific to your existing code and is about what useful smaller functions to extract there and how to combine them.
For this one would need to have your full code and understand it. That might be a bit much for this QA format.
Clarification:
I'm not interested in using jQuery methods.
Summary
I use a method to only run my modules after the html has finished loading. It looks like this. page_complete is the id of the last element on the page.
$A.finish('page_complete', function () {
// page has finished loading
});
Finish is implemented like this. It is just a timer that checks of the existence of the last element. Once it finds it, it initializes all the modules.
I don't understand why the element is NULL as FF is telling me.
/*finish
** Once an element has been loaded an HTML focus event is fired
** on that ID. It can not be cancelled and bubbles up
**
*/
$A.finish = function (id, callback) {
var htm_finished = document.getElementById(id);
if (htm_finished) {
$A.initAll(); // intilAll will fire the init function of all modules.
$A.makeEvent('focus', htm_finished);
callback();
} else {
setTimeout(function () {
$A.finish(id, callback);
}, 10);
}
};
Error in Firefox
...TypeError: this.E.ready is null # ...
Note I put a comment where the error is.
Module with error
/*MUserAny
**
**
**
*/
$A.module({
Name: 'MUserAny',
S: {
DynSma: SDynSma,
DynTwe: SDynTwe,
DynArc: SDynArc,
AniFlipMediaPane: SAniFlipMediaPane,
AniFlipPage: SAniFlipPage,
ClientStorage: SClientStorage
},
E: {
ready: $A('#page_complete')[0]
},
init: function () {
var pipe = {},
this_hold = this;
this.E.ready.addEventListener("focus", function (event) { // error is here.
pipe = $A.definePipe(this_hold.Name);
$A.machine(pipe);
}, false);
},
pre: function (pipe) {
var h_token = this.S.ClientStorage.get('h_token');
if ((h_token === '0') || (h_token === 'undefined') || (h_token === null)
|| (h_token === undefined)) {
this.S.AniFlipPage.run('sp');
pipe.state = false;
} else {
pipe.server.smalls.h_token = h_token;
pipe.state = true;
}
this.S.AniFlipMediaPane.run('mi_cover');
return pipe;
},
post: function (pipe) {
this.S.DynSma.run(pipe.server.smalls);
this.S.DynArc.run(pipe.server.arcmarks);
this.S.DynTwe.run(pipe.server.tweets);
this.S.AniFlipPage.run(this.S.ClientStorage.get('page'));
return pipe;
},
finish: function (pipe) {
}
});
It looks like
E: {
ready: $A('#page_complete')[0]
}
is being evaluated as part of the object literal, and if this is occuring before the page is complete you get your error.
One quick and dirty solution may be to change E.ready to a function, which will only be called during init, which you know happens after page complete, something like
E: {
ready: function() { return $A('#page_complete')[0]; }
},
init: function () {
var pipe = {},
this_hold = this;
this.E.ready().addEventListener("focus", function (event) { ...
The code looks like this
function Scripts() {this.FindById = function (id) {
this.FindById.constructor.prototype.value = function () {
return document.getElementById(id).value;
}}}
var Control = new Scripts();
Now when i say Control.FindById("T1").value(). I am not able to get the textInput("T1")'s value.
It seems that your code is a bit more complicated then it should be ;-)
Personally I would write it this way (not tested):
function Scripts() {
this.findById = function(id) {
var el = document.getElementById(id);
return {
value: function() {
return el.value;
}
}
}
}
The findById() now closes over a node and returns an interface that can return its value.
Also, your idea sounds a lot like Singleton, so you wouldn't even need the extra Scripts constructor:
var Control = {
findById: function(id) {
var el = document.getElementById(id);
return {
value: function() {
return el.value;
}
}
}
}
Working example: http://jsfiddle.net/YYkD7/
Try this:
function Scripts() {this.FindById = function (id) {
this.FindById.constructor.prototype.value = function () {
return document.getElementById(id).value
}}}
You didn't close the last "}" :-)
I have searched and read for a few hours yet I still cant understand the basic design pattern for creating a new object that has a choice of different methods (of the same name) that is set dependant on one of the arguments. here's some code to explain what I am trying to do.
All advice and alternative approaches welcome. I hope someone can emancipate me form this cloud of ignorance.
Thanks
function BaseConstructor(whichMethods) {
if (whichMethods==='a') {
// do something to incorporate methodSetA
}
else if (whichMethods==='b') {
// do something to incorporate methodSetB
}
this.init();
};
var methodSetA = {
init: function() {
// do initialisation A way
},
speak: function() {
alert('i speak AAA way')
}
};
var methodSetB = {
init: function() {
// do initialisation B way
},
speak: function(){
alert('i got BBB all the way')
}
};
thing = new BaseConstructor('b');
// b is an instance of BaseConstructor and has done the bWay init() function
thing.speak() // return alert 'i got BBB all the way'
You can do it like this using a factory function (a regular function that creates the appropriate object for you):
function BaseConstructor(whichMethods) {
var elem;
if (whichMethods==='a') {
elem = new MethodSetA();
} else if (whichMethods==='b') {
elem = new MethodSetB();
} else {
// figure out what to do here if whichMethods is neither of the previous options
}
elem.init();
return(elem);
};
And invoke it as a regular function call:
var thing = BaseConstructor('b');
thing.speak();
Note: there is no use of new with BaseConstructor() as it's a regular function call.
Well, to do it your way using "method sets," you can iterate and copy into this (here's a demo):
function copy(source, destination) {
for(var x in source) {
if(source.hasOwnProperty(x)) {
destination[x] = source[x];
}
}
}
function BaseConstructor(whichMethods) {
if(whichMethods === 'a') {
copy(methodSetA, this);
} else if(whichMethods === 'b') {
copy(methodSetB, this);
}
this.init();
}
Personally, though, I'd prefer to assign directly to this.
You are looking for factory pattern.
Example:
function objectFactory(whichMethods) {
if (whichMethods==='a') {
return new objectSetA();
}
else if (whichMethods==='b') {
return new objectSetB()
}
};
function objectSetA() {
this.init = function() {
// do initialisation A way
},
this.speak = function() {
alert('i speak AAA way')
}
};
function objectSetB() {
this.init = function() {
// do initialisation B way
},
this.speak = function(){
alert('i got BBB all the way')
}
};
var thing = objectFactory('b');
thing.speak();