Shorthand Shortcircut. Is it possible to do some stuff - javascript

This question is about a TypeScript code-base, but the general concepts that underpin it are ECMAScript concepts, therefore; I have tagged the question as both JS & TS. If I should tag it differently, you can either let me know, or make the edit yourself and I will accept it if I see it.
In a TypeScript document, I have defined an object-type that contains 4 string typed properties.
Here is an example of the type
type StrObjType = {
foo?: string;
boo?: string;
fuz?: string;
buz?: string;
}
Along with the object described above, I have a function — its called funkyFunc — with a parameter that takes an argument of type StrObjType.
This is what the function looks like:
function funkyFunc(obj:StrObjType)
{
let mesg = '';
if(obj.foo){ mesg += '\n Foo: ' + obj.foo; }
if(obj.boo){ mesg += '\n Boo: ' + obj.boo; }
if(obj.fuz){ mesg += '\n Fuz: ' + obj.fuz; }
if(obj.buz){ mesg += '\n Buz: ' + obj.buz; }
if(!mesg) return '';
// If a string was concatenated to mesg, return w/ newline appended
return mesg + '\n';
}
About the Function
If you can't tell by looking at it, the function creates a list using only properties that were added to the functions object-argument. The new-lines ('\n') are added as a means to format the list.
You can see in the function that each property in the object's type is checked for a truthy value. When a property is truthy, the props string-value is appended to the mesg variable via the "Addition Assignment Operator".
About the Problem & Solution
What I'd like to know, is if there is a better way to write the if statements, if I can short circuit them, or use a shorthand. Here is an example of a short circuit that uses nullish coalescing. The link shows a short circuit used to check an objects property, and assign it, only if the property is non-nullish (null or undefined). I was hoping to use that operator, but becauese I am appending the value when the property exist, rather than assigning it, the nullish coalescing won't seem to work.
Nevertheless, I can't help but to feel like this is the ideal situation for implementing a short circuit, but if there is a better way to write the function, I can't figure out what it is.
There is this way of writing it, but IDK if it's better.
let mesg = '';
mesg += obj.foo ? '\n Foo: ' + obj.foo : undefined;
mesg += obj.boo ? '\n Boo: ' + obj.boo : undefined;
mesg += obj.fuz ? '\n Fuz: ' + obj.fuz : undefined;
mesg += obj.buz ? '\n Buz: ' + obj.buz : undefined;
if (!mesg) return '';
return mesg + '\n';
}
The problem with the above method of writing the function is that it requires using the JS built-in undefined constant, and that feels hacky to me, as the undefined constant wouldn't be needed otherwise. I could replace the undefined constant with an empty string I guess, but it still doesn't feel right, as it requires adding a nullish value, which are values I typically try to avoid (not that I see any immediate harm that comes from using undefined, or '').
So I guess my question is this...
Is there a shorthand, or short-circuit I can use to eliminate the if keywords in the first function example I added? The short circuit or shorthand cannot be the ternary example I already provided, and it needs to shorten the codes length, or improve the codes readability.
If there is any confusion, or if the question just isn't making sense, let me know, I will clear things up. I am peer reviewed, and I feel like there is something I am missing here. I would like to feel more confident about how I am authoring this function.

There is this way of writing it, but IDK if it's better.
What you have after the text above will result in the string "undfined" appearing in mesg, which I assume you don't want. :-) If you wanted to do it that way, you'd use "", not undefined, for the third operand of the conditional operators:
mesg += obj.foo ? "\n Foo: " + obj.foo : "";
mesg += obj.boo ? "\n Boo: " + obj.boo : "";
mesg += obj.fuz ? "\n Fuz: " + obj.fuz : "";
mesg += obj.buz ? "\n Buz: " + obj.buz : "";
What I'd like to know, is if there is a better way to write the if statements, if I can short circuit them, or use a shorthand.
Not really. Moreover, what you have with the if statements (or the series of conditional operator expressions) is clear and easy to debug. There are other ways to do it, but they may be harder for people coming to the code fresh to understand.
For example, you could have this constant:
const messageParts = [
{key: "foo", label: "Foo"},
{key: "boo", label: "Boo"},
{key: "fuz", label: "Fuz"},
{key: "buz", label: "Buz"},
] as const;
(The as const is important, that way TypeScript can see that the key values are valid keys for StrObjType.)
Then the code is something like:
for (const {key, label} of messageParts) {
const value = obj[key];
if (value) {
mesg += `\n ${label}: ${value}`;
}
}
Playground link
For a one-off, that's definitely not an improvement, and it's certainly not short-circuiting or shorthand. But if there are a lot of places you use this same information, it gives you just one place to maintain it.
But if it's a one-off just to build mesg, I think you're best off with the ifs you already have, or the conditional operator expression alternative you noted (with the undefined => "" fix).

Related

LineBreak in console object

Line break in javascipt string console
console.log("Foo" + "\n" + "Bar");
Line break in javascript object console
console.log({ value : "Foo\nBar" });
Is it possible to add linebreaks in javascript objects.
The answer is no: when you print an object to the console log, strings will be written as javascript objects (similar but not identical to what you'd get if you explicitly converted them into JSON, like console.log(JSON.stringify(object))).
If you want for some reason to print your strings with line breaks, you'd have to implement the object-to-string conversion yourself; perhaps with something like this:
function customString(object) {
let string = '{\n';
Object.keys(object).forEach(key => {
string += ' "' + key + '": "' + object[key] + '"\n';
});
string += '}';
return string;
}
console.log(customString({ value: "Foo\nBar" }));
(It sounds like you have an idea in mind of exactly how you want this output to look, so adjust the function above until it works as expected.)
You can make JSON pretty with automatic line breaks using:
console.log(JSON.stringify({ test: { key: { inner: 'val' } }}, null , 2))
Where 2 is the number of spaces/indent for each level.
You can use ES6:
console.log(`hello
world`)
will produce:
hello
world
I think its originally creating a line break, but due to the object, it's not showing directly. Try to assign it in variable and access that in the console.
Code:
var v = {val:"test\ntest"};
console.log(v.val);
Output:
test
test

AngularJs $parse string to object

So lets say I have a server that returns a string like:
{
add:function(a,b) {
return a+b;
},
subtract:function(a,b) {
return a-b;
}
}
is it possible to $parse that into a function?
I tryed to parse it with:
$parse(element.Content) // Content is the string above
but get
Token '{' is an unexpected token
I would like something like:
elementFunctions = $parse(element.Content)
$parse does not do what you think it does!
To put it simply, it just resolves properties, by their name, against some context (angular scopes) -- basically.
Well, it's more than that, it provides a way to interact with these properties, but you'll get the gist of it by having a quick look at its documentation.
It does not evaluate Strings as javascript code.
You're most likely looking to evaluate your string.
Although in many, many cases there's a better, faster, more controllable and more reasonable solution!
const code = ''
+ 'const functions = {'
+ 'add: function(a,b) {'
+ 'return a+b;'
+ '},'
+ 'subtract: function(a,b) {'
+ 'return a-b;'
+ '}'
+ '};'
+ 'functions';
console.log(eval(code).add(50, 1));

How to invoke javascript in WebView Windows 10 UWP?

I am trying to load a javascript in WebView to do some calculations and get the output in a string. I tried to use following code
string htmlFragment = "<html><head><script type='text/javascript'>" +
"function doubleIt(incoming){ " +
" var intIncoming = parseInt(incoming, 10);" +
" var doubled = intIncoming * 2;" +
" document.body.style.fontSize= doubled.toString() + 'px';" +
" return doubled.toString());" +
"};" +
"</script></head><body>" +
"<div id = 'myDiv'>I AM CONTENT</div></body></html>";
htmlView.NavigateToString(htmlFragment);
htmlView.LoadCompleted += async(s1,e1) =>
{
string result = await htmlView.InvokeScriptAsync("eval", new string[] { "doubleIt(25)" });
Debug.WriteLine(result);
};
Update
I am able to load simple javascript easily now based on help provided in the answer. But now I am facing issues when there is more than one function in javascript, I am getting an exception. I am trying the following code
string htmlFragment = #"<html><head><script type='text/javascript'>" +
"function a(){return 10;};" +
"function b(){return 20;};" +
"function c(){return 30;};" +
"return (a()*b()*c());" +
"</script></head><body>" +
"<div id = 'myDiv'>I AM CONTENT</div></body></html>";
Please suggest.
The documentation for this feature is really poor. It took me some time to figure out how to invoke Javascript in UWP WebView
When you first look at the function call webView.InvokeScriptAsync(string,string[]) your initial reaction is that they want the function name as the first parameter and then the function paramaeters as the string array. (mainly because the MSDN documentation says this)
Parameters
scriptName
Type: System.String [.NET] | Platform::String [C++]
The name of the script function to invoke.
arguments
Type: System.String[]
[.NET] | Platform::Array [C++]
A string array that
packages arguments to the script function.
HOWEVER, this is wrong and will lead to hours of head banging. REALLY, what they want is the word "eval" in the first parameter and then a string array of functions, and or commands you wish to eval
var value = await webViewer.InvokeScriptAsync("eval",
new string[]
{
"functionName(functionParams)"
});
Having worked with Microsoft APIs for a few years now I am convinced that this is not the intended way of consuming this function and is a bit of a hack. Unfortunately if you want to consume JavaScript this is the only way that I know that works currently.
Anthony,
Try to check your own suggestion:
await webViewer.InvokeScriptAsync("eval",
new string[]
{
"functionName(functionParams)"
});
or:
await webViewer.InvokeScriptAsync(functionName, new string[]{ functionParameters });
The same as Microsoft suggests, just you are limiting a function name by one ("eval") - not necessary. Trust me, you can use any function name, as I am now with UWP and before with windows phone hybrid apps.
The question is already 4 years old, but I'm coming to see why you were getting an empty string as a result.
In your example, the functions in JavaScript return integers while the expected value is of type string.
By modifying these functions and returning a string like this:
string htmlFragment = #"<html><head><script type='text/javascript'>" +
"function a(){return '10';};" +
"function b(){return '20';};" +
"function c(){return '30';};" +
"</script></head><body>" +
"<div id = 'myDiv'>I AM CONTENT</div></body></html>";
We get the good result on the way back.

Javascript - concat string does not work as expected

What's the wrong with this Javascript line?
user: h.reem
domain: somedomain
var target = "//account/win/winlogin.aspx" +
"?username=" +
user.toString() +
"&domain=" +
domain.toString();
the resutl is always:
//account/win/winlogin.aspx?username=h.reem
Any idea!!
alert(user + "X") shows only h.reem
The ActiveX component is probably returning a null terminated string (I've seen this with Scripting.TypeLib & a couple of the AD objects for example) so concatenating it with another string fails. (You can verify this if 0 === user.charCodeAt(user.length - 1)).
You will need remove the last character before using the string;
user = user.substr(0, user.length - 1);
try:
var sUser = user.toString();
var sDomain = domain.toString();
var target = "//account/win/winlogin.aspx" + "?username=" + sUser + "&domain=" + sDomain;
The above might not fix your problem but it should expose it - Could be that your user.toString() method isn't returning a string and is short-circuiting things... If this doesn't answer your question I'd be glad to assist further, but it would be helpful if you posted the implementation or source of "user" somewhere ...

searching equivalent function/way to "list()" from php

i'm searching for an equivalent function for php's "list()". i'd like to split a string with "split()" and put the array values in two different variables. hopefully there's another way to do this as short and performance-optimized as it could be.
thanks for your attention!
Here's a list implementation in javascript:
http://solutoire.com/2007/10/29/javascript-left-hand-assignment/
Maybe PHP.JS is worth looking at (for future stuff maybe). I noticed that the list() was only experimental though but maybe it works.
If you can live without the naming, you can do this:
var foo = ["coffee", "brown", "caffeine"];
foo[0] + " is " + foo[1] + " and " + foo[2] + " makes it special";
Alternatively, use a object to name the keys:
var foo = {drink: "coffee", color: "brown", power: "caffeine"};
foo.drink + " is " + foo.color + " and " + foo.power + " makes it special";
I think the closest you can get is the explicit
var args = inputString.split(",");
// Error checking, may not be necessary
if (args.length < 3)
{
throw new Error("Not enough arguments supplied in comma-separated input string");
}
var drink = args[0];
var color = args[1];
var power = args[2];
since Javascript doesn't have multiple assigment operators. I wouldn't worry too much about the efficiency of this; I expect that the list function in PHP basically boils down to the same thing as above, and is just syntactic sugar. In any case, unless you're assigning hundreds of thousands of variables, the time to execute anything like the above is likely to be negligible.

Categories