I'm trying to create a talk page link that changes based on what namespace you might be in. For instance if you're in mainspace you'll be directed to Talk: if in category to Category_talk:. I have this so far:
var namespace = if (wgNamespaceNumber == '0') {
return ('Talk');
} else {
return (mw.config.get( 'wgCanonicalNamespace' ) + '_talk');
}
But it's just returning a syntax error, unexpected token if. I'm guessing you can't use if in this way?
return is for passing a value or object out of a function, not blocks like if/else.
var namespace;
if (wgNamespaceNumber == '0') {
namespace = 'Talk';
} else {
namespace = mw.config.get( 'wgCanonicalNamespace' ) + '_talk';
}
You guessed right. You can't assign an IF like that.
Change your code into
var namespace = null;
if (wgNamespaceNumber == '0') {
namespace = 'Talk';
} else {
namespace = (mw.config.get( 'wgCanonicalNamespace' ) + '_talk');
}
And it'll work.
You don't need to return anything. You can just set the value of the variable based on the condition. The function will however need to return a value.
var namespace = (wgNamespaceNumber == '0')
? 'Talk'
: mw.config.get( 'wgCanonicalNamespace' );
The condition above is called a ternary (MDN explains it better)
Related
This is a very basic issue about if statements. It doesn’t necessarily effect only javascript.
If object.user is undefined this will break:
if ( object.user.name ) {
sayMyName();
} else {
object.user = {};
object.user.name = 'Jane Doe';
sayMyName();
}
because it can not read a property of undefined. So i put the else stuff in a function and folded the if into another if:
function anonymous(object) {
object.user = {};
object.user.name = 'Jane Doe';
sayMyName();
}
if ( object.user ) {
if ( object.user.name ) {
sayMyName();
} else {
anonymous();
}
} else {
anonymous();
}
But this looks like bad code to me. This case must be a common problem. Or at least i have it quite often. Is there any good solution for this?
EDIT:
#Mritunjay's proposal
if(object && object.user && object.user.name){...}
is way better, but it doesn’t seem to be the best solution. Imagine a if-statements that tries to get obj.some.very.very.deep.property. I‘m currently trying to write a helper-function like checkPropertySafely(object.user.name); that goes back to object, and checks every property recursively, no matter how deep it is. So basically i try to automate #Mritunjay’s manually written statement.
I use bellow in this situation
if(object.user && object.user.name){...}
BTW you should check if object also exists.
if(object && object.user && object.user.name){...}
I finally figured out how to write the helper-function. Here it is:
function propertyExists(property) {
var statement = '';
var prevItem = '';
property.split(".").forEach(function(item, index) {
if (index != 0) {statement += ' && '}
statement += prevItem+item;
prevItem += item+'.';
});
return eval(statement);
}
With this function, i can now simply do this:
if ( propertyExists('object.user.name') ) {
sayMyName();
} else {
anonymous();
}
At the moment I have duplicate code where I have the following examples:
if ($scope.user.window.title == 'true'){
if (this.title){
title = '<h2>'+this.title+'<h2>';
} else {
title = '';
}
} else {
title = '';
}
if ($scope.user.window.football == 'true'){
if (this.football){
football = '<p>'+this.football+'<p>';
} else {
football = '';
}
} else {
football = '';
}
I have tried the following but it doesn't work, it says that the $scope.user.window.football and $scope.user.window.title don't exist. I think it is down to the below function sending the value through as a string for my $scope.
function CheckWindow(element,tag) {
console.log(element);
if ($scope.user.window.element == 'true'){
if (this.element){
element = '<'+tag+'>'+this.element+'</'+tag+'>';
} else {
element = '';
}
} else {
element = '';
}
}
Usage
CheckWindow('title','h2')
CheckWindow('football','p')
$scope.user.window.element tries to access the property named element of $scope.user.window. You need $scope.user.window[element] instead.
this refers to the created function's scope. You could pass a new argument that for example.
that.element will have to be rewritten to that[element], for the same reason as in #1.
You can't assign a new value to a function's parameter (well, you can, but it won't be accessible outside the function's scope). Better return the value.
So:
function CheckWindow(that, element, tag) {
if ($scope.user.window[element] && that[element]){
return '<'+tag+'>'+that[element]+'</'+tag+'>';
}
return '';
}
title = CheckWindow(this, 'title', 'h2');
football = CheckWindow(this, 'football', 'p');
try
$scope.user.window[element]
When you need to reference a property as a sttring, you must use bracket notation.
Also, I doubt that 'this' will reference what you want. You may need to angular.bind this to the method.
Often writing function's code I need to make sure certain values are defined or I want immediately return false value. But writing whole if block feels too much typing. Is it possible to write instead of:
function getSomethingByModel(model) {
var id = model.id;
if (! id) {
return;
}
// rest of the code
}
Something like this:
function getSomethingByModel(model) {
var id = model.id || return;
// rest of the code
}
This is pure aesthetics question, not functional one.
To some extent, you can use the && operator to accomplish this and avoid cumbersome if statements:
function getSomethingByModel(model) {
var id = model && model.id,
thing = id && getThingById(id),
otherThing = thing && getOtherThingFromThing(thing);
return otherThing || null; // or alternatively, just return otherThing;
}
If any stage of the process produces a falsey value, the logic will just quickly fall through to the end and return null (or the first falsey value encountered if you use the alternative return statement above).
You could define all your properties at the top of the function (or wherever, because hoisting), then use the side-effects of assignment to cause a return. For example:
function getSomethingByModel(model) {
var id;
if(!(id = model.id)) return false;
// rest of the code
}
I'm trying to follow the rule and avoid repeating the same code.
I have this single function but depending on the input I want it to either return an array of objects or an object (not an array of just one object)
e.g.(the actual function is much longer and more elaborate than this one obviously, there are just the last few lines after a much longer calculation)
function (nameParameter, ageParameter, inputType)
{
if (inputType === "asObject")
{
var x = {};
x.name = nameParameter;
x.age = ageParameter;
return x;
}
else if (inputType === "asArray")
{
var y = [];
y.push(nameParameter);
y.push(ageParameter);
return y;
}
};
Is this possible and if so is it good practice? Is there some other way around it?
Otherwise I'll have to create two distinct function with almost the exact same code.
Don't do this. Implement one version and add a wrapper function that converts the the other format you may want. That way the caller always gets consistent behaviour, and theres still no code duplication.
function asObject(nameParameter, ageParameter)
{
//Lots of work here.
var x = {};
x.name = nameParameter;
x.age = ageParameter;
return x;
};
function asArray(nameParameter, ageParameter)
{
//Just defer to the other version and repack its response.
var o = asObject(nameParameter, ageParameter);
var y = [o.nameParameter,o.ageParameter ];
return y;
}
You can simplify your code by declaring the object and array with the values already set, but in my opinion if you have this strict type of coding it is not necessary to keep this function... Anyway, here is a simplified version:
function (nameParameter, ageParameter, inputType) {
var ret;
if (inputType === "asObject") {
ret = {
name: nameParameter,
age: ageParameter
};
} else if (inputType === "asArray") {
ret = [nameParameter, ageParameter];
}
return ret;
};
I left it without name and with a semicolon at the end because I guess it has been declared through a variable.
Yes; that will work fine.
Javascript is not strongly-typed; functions can return whatever they want, whenever they want.
if ( typeof inputType == 'object') {
//object part of code
} else {
//array part of code
}
Here is the line which is causing null or not an object error
if(frm.elements["hdn_retain"+indexval].value==""){
....
} else {
....
}
frm.elements["hdn_retain"+indexval] may be a null object. So, it will have error when getting the value. You can check the frm.elements["hdn_retain"+indexval] if it is null first.
if(frm.elements["hdn_retain"+indexval] != null && frm.elements["hdn_retain"+indexval].value=="")
Either frm or frm.elements["hdn_retain"+indexval] isn't a valid object (doesn't exist in the dom) and therefore you can't access it's property.
you could try something like:
if(frm.elements["hdn_retain"+indexval] && frm.elements["hdn_retain"+indexval].value==""){
Following is the result of alert statement:
alert("frm:::"+frm);
alert("frm elements::::"+frm.elements);
alert("frm hdn_retain :: "+frm.elements["hdn_retain"+indexval]);
frm:::[object]
frm elements::::[object]
frm hdn_retain :: undefined
you can use this utility method getProperty i always use to make sure i get a nested namespace back without worrying about whether or not something is defined:
function getProperty(ns, obj) {
var nsArray = ns.split('.'),
i = 0,
nsLen = nsArray.length;
while (nsLen > 0) {
var newNs = nsArray.shift();
if (obj[newNs]) {
obj = obj[newNs];
} else {
return false;
}
nsLen = nsArray.length;
}
return obj;
};
var index = "hdn_retain" + indexval;
// the following `value` will come back as a valid object/value or a false
value = getProperty('elements.' + index + '.value', frm);
if (value) {
// do whatever
} else {
// do not whatever
}
this can be applied not only to this situation but to any other situation you need to make sure a certain namespace is available before usage.