JavaScript: SyntaxError: missing ) after argument list - javascript

I am getting the error:
SyntaxError: missing ) after argument list
With this javascript:
var nav = document.getElementsByClassName('nav-coll');
for (var i = 0; i < button.length; i++) {
nav[i].addEventListener('click',function(){
console.log('haha');
}
}, false);
};
What does this error mean?

You have an extra closing } in your function.
var nav = document.getElementsByClassName('nav-coll');
for (var i = 0; i < button.length; i++) {
nav[i].addEventListener('click',function(){
console.log('haha');
} // <== remove this brace
}, false);
};
You really should be using something like JSHint or JSLint to help find these things. These tools integrate with many editors and IDEs, or you can just paste a code fragment into the above web sites and ask for an analysis.

You got an extra } to many as seen below:
var nav = document.getElementsByClassName('nav-coll');
for (var i = 0; i < button.length; i++) {
nav[i].addEventListener('click',function(){
console.log('haha');
} // <-- REMOVE THIS :)
}, false);
};
A very good tool for those things is jsFiddle. I have created a fiddle with your invalid code and when clicking the TidyUp button it formats your code which makes it clearer if there are any possible mistakes with missing braces.
DEMO - Your code in a fiddle, have a play :)

just posting in case anyone else has the same error...
I was using 'await' outside of an 'async' function and for whatever reason that results in a 'missing ) after argument list' error.
The solution was to make the function asynchronous
function functionName(args) {}
becomes
async function functionName(args) {}

Similar to Josh McGee, I was trying to use await in the global scope, which, since it isn't an async function, will throw an error. See here for solutions.

This error maybe is the version of your Android (especially if you are using Web Views), try to change your code like an old version of the JavaScript Engine, like:
.then(function(canvas){
//canvas object can gained here
});

This error can also occur if you are missing a (tick) '
Failed:
if (!string.IsNullOrWhiteSpace(clientSideMethod))
{
return "function(e){" + clientSideMethod + " OnOptionChangedDxGrid(e," + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
else
{
return "function(e){ OnOptionChangedDxGrid(e," + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
Worked:
public static string GetOnOptionChangedMethodCall(string clientSideMethod, bool hasConditionalFormatting)
{
if (!string.IsNullOrWhiteSpace(clientSideMethod))
{
return "function(e){" + clientSideMethod + " OnOptionChangedDxGrid(e,'" + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
else
{
return "function(e){ OnOptionChangedDxGrid(e,'" + hasConditionalFormatting.ToString().ToLower() + "','" + "false".ToString().ToLower() + "', '" + string.Empty + "'); }";
}
}
Notice there is a missing (tick) ` before the first double quote: (e," + hasConditionalFormatting.ToString()

I got the same error and I figured with the increased use of ES6 and string interpolation, that more and more people would start making the same mistake I did with Template Literals:
Initially, I logged a statement like so:
console.log(`Metadata: ${data}`);
But then changed it and forgot to remove the ${}:
console.log('Metadata: ' + JSON.stringify(${data}));

Related

Uncaught TypeError: Cannot read property '0' of undefined beqause it is unexistant

what is the best way to say devenitions=true? i cant figgure it out...
if (!defenitieGetoond) {
getDef();
defenitieGetoond = true;
} else {
getWoord();
defenitieGetoond = false;
}
This is my loop who expects that there is always a defenition? but in my json file this is not always the case. it searches to the Json file as follows.
function getDef() {
document.getElementById("demo_").innerHTML = "<br>" + savedWord[1].definitions[0].definition
// + "<br>" + "</br>"+ savedWord[1].definitions[1].definition
;
}
it needs to skip of ignore the Deffenitions[0] som how
You should need to add check in case of element exist or not. like this -
function getDef(){
const ele = document.getElementById("demo_");
if (savedWord[1].definitions && savedWord[1].definitions.length) {
ele.innerHTML = "<br>" + savedWord[1].definitions[0].definition
// + "<br>" + "</br>"+ savedWord[1].definitions[1].definition;
}
}

Array gives errors after JSON function

I'm trying to check if the twitch stream is online or offline and if so change a background colour. If i check without the array and just put in the name it works, but with the array it doesn't (I don't have a lot of knowledge of JSON).
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
for (var i = 0; i < twitchChannels.length; i++) {
console.log(i + " " + twitchChannels[i]);
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', function(channel) {
console.log(i + " " + twitchChannels[i]);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannels[i])
document.getElementById(twitchChannels[i]).style.backgroundColor = "red";
} else {
console.log("Online: " + twitchChannels[i])
document.getElementById(twitchChannels[i]).style.backgroundColor = "green";
}
});
}
}
Error: http://prntscr.com/i6qj51 inside the red part is what happens inside of json fuction
Your code is quite weak since you didn't manage the callback of every get you make.
Also you didn't check if:
document.getElementById(twitchChannels[i])
is null, since the exception clearly stated that you can't get :
.style.backgroundColor
from nothing.
Basic check VanillaJS:
if(!document.getElementById("s"))
console.log('id ' + twitchChannels[i] + ' not found in dom')
else
console.log('id ' + twitchChannels[i] + ' found in dom')
Also consider mixing JQuery with VanillaJS extremely bad practice; use proper JQuery method to access dom element by ID .
You should pass twitchChannel to the function because the var i is changing, this is an issue like others already mentioned: Preserving variables inside async calls called in a loop.
The problem is that you made some ajax call in a cicle, but the ajax calls are async.
Whey you get the first response, the cicle is already completed, and i==4, that is outside the twitchChannels size: that's why you get "4 undefined" on your console.
You can change your code in such way:
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
for (var i = 0; i < twitchChannels.length; i++) {
executeAjaxCall(twitchChannels[i]);
}
}
function executeAjaxCall(twitchChannel){
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannel + '?client_id=XXXX', function(channel) {
console.log(twitchChannel);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannel)
$('#'+twitchChannel).css("background-color", "red");
} else {
console.log("Online: " + twitchChannel)
$('#'+twitchChannel).css("background-color", "green");
}
});
}
}
When console.log(i + " " + twitchChannels[i]); is called inside the callback function, the variable i has already been set to 4, and accessing the 4th element of array twitchChannels gives undefined since the array has only 4 elements.
This is because $.getJSON is a shorthand Ajax function which, as the name suggests, executes your requests asynchronously. So what actually happened is, based on the output you provided,
The loop is executed 4 times, and four Ajax requests have been sent.
The loop exits; i is already set to 4 now.
The ajax requests return; the callbacks are called, but the i value they see is now 4.
You can change the console.log inside your callback to something like console.log(i + " " + twitchChannels[i] + " (inside callback)"); to see this more clearly.
The correct result can be obtained by binding the current value of i to the closure.
function test() {
var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];
function make_callback(index) {
return function (channel) {
console.log(index + " " + twitchChannels[index]);
if (channel["stream"] == null) {
console.log("Offline: " + twitchChannels[index])
document.getElementById(twitchChannels[index]).style.backgroundColor = "red";
} else {
console.log("Online: " + twitchChannels[index])
document.getElementById(twitchChannels[index]).style.backgroundColor = "green";
}
}
}
for (var i = 0; i < twitchChannels.length; i++) {
console.log(i + " " + twitchChannels[i]);
$.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', make_callback(i));
}
}

Organise javascript webdriver promises code idiomatically

I am asserting on the contents of a particular row from an html table using webdriver via protractor. I have the following code which works correctly, but looks horrible. I want advice on how to better organise this code idiomatically with promises; in particular, I'd like to make it more obvious that there are 3 parts to this code:
Find the rows with a td containing the specified matchText on the page
Check that only one row matched, and handle the error cases with useful debug info
Check that the text content of the tds in this matched row is as expected
Is there a way I can organise this better to make this more readable, perhaps by chaining the promises or something?
browser.findElements(by.xpath("//td[text() = '" + matchText + "']/..")).then(function(trs) {
if (trs.length == 0) {
throw 'Unable to find td element equal to ' + matchText
} else if (trs.size > 1) {
protractor.promise.all(trs.map(function(tr){return tr.getInnerHtml()})).then(function(trsInnerHtml) {
throw 'Matched multiple td elements for ' + matchText + ':' + trsInnerHtml;
})
} else {
trs[0].findElements(by.tagName('td')).then(function(tds) {
protractor.promise.all(tds.map(function(td) {return td.getText()})).then(function(tdContent){
expect(tdContent).toEqual(expectedContent);
})
});
}
});
Yes, you can unwrap the promise callbacks from the non-throw case to a chained version:
browser.findElements(by.xpath("//td[text()='" + matchText + "']/..")).then(function(trs) {
if (trs.length == 0) {
throw 'Unable to find td element equal to ' + matchText
} else if (trs.size > 1) {
return protractor.promise.all(trs.map(function(tr) {
return tr.getInnerHtml()
})).then(function(trsInnerHtml) {
throw 'Matched multiple td elements for ' + matchText + ':' + trsInnerHtml;
});
} else {
return trs[0].findElements(by.tagName('td'));
}
}).then(function(tds) {
return protractor.promise.all(tds.map(function(td) {return td.getText()}));
}).then(function(tdContent){
expect(tdContent).toEqual(expectedContent);
});
How about using element, element.all() and letting expect() resolve the promises for us and get some help from jasmine-matchers package that introduces a handy toBeArrayOfSize() matcher:
element.all(by.xpath("//td[text() = '" + matchText + "']/..")).then(function(trs) {
expect(trs).toBeArrayOfSize(1);
expect(trs[0].element(by.tagName('td')).getText()).toEqual(expectedContent);
});
In the end I took chaining promises from #Bergi and the element api from #alexce (thanks both!) and came up with this:
it('Matches tds', function() {
browser.get('index.html');
var textToMatch = 'TDs';
expect(
element.all(trsContainingTd(textToMatch)).then(extractTds)
).toEqual(
[['Expected', 'TDs', 'content']]
);
});
function trsContainingTd(matchText) {
return by.xpath("//td[text() = '" + matchText + "']/..");
}
function extractTds(trs) {
return protractor.promise.all(trs.map(function(tr) {
return tr.all(by.tagName('td')).getText();
}));
}
This has a few advantages to my eye:
It's a single expectation
It will print out the helpful debug if there are more / fewer matching rows than expected
The trsContainingTd and extractTds functions are general enough to be used elsewhere

How would you create a call to a function inside a for loop? [duplicate]

I'm new to node, but I love it already. Only issue is, the asynchronous functionality is killing me.
I am using the google package to get my websites' rankings in google as so:
for (var j=0;j<keywords.length;j++) {
var keyword = keywords[j];
google(keyword, function(err, next, links) {
console.log('Searching for keyword "' + keyword + '" in google.' + google.tld + ' ('+ google.lang +')');
if (err) console.error(err);
for (var i = 0; i < links.length; ++i) {
var rank = i+1;
console.log(keyword + ' #'+ rank + ' - ' + links[i].link + ' | ' + links[i].title);
//link.href is an alias for link.link
//console.log(links[i].description + "\n");
}
console.log('\n');
});
}
My problem is that it the console log shows the same keyword for all websites, although I have defined three in my keywords array.
What am I missing?
The immediate problem here is that the j and keyword variables go on changing before the callbacks are called.
A simple solution is to protect this variable in a closure :
for (var j=0; j<keywords.length; j++) {
(function(j){
var keyword = keywords[j];
...
})(j);
}
When you're just working with a simple array, then you can also use a closure through forEach :
keywords.forEach(function(keyword, j){
...
});
To deal with this kind of asynchronous problems, you should now dive in promises which help structure your code in a clearer (and less indented) way. An introduction.

SDK GridRefresh Call Throwing Exception

I'm going to try to explain this as best I can, please feel free to ask for clarifications as required.
Using IE10, CRM Online with RU12.
I am playing about with subgrids and getting them to refresh. Consider the following script, which I have nicked wholesale from MSDN (and wrapped in a try/catch block)
function start() {
try {
var controls = Xrm.Page.ui.controls.get(isSubGrid);
if (controls.length > 0) {
var subGridNames = "";
for (var i in controls) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
alert("The following subgrids were refreshed: \n" + subGridNames);
}
else {
alert("There are no subgrid controls on the current form.");
}
}
catch (ex) {
alert(ex);
}
}
function isSubGrid (control)
{
return control.getControlType() == "subgrid";
}
Nothing special going on there - get all controls of type subgrid (this returns 10 elements as expected) and call refresh() on them.
However this is consistently failing on the first call to refresh().
The exception details is fairly straightforward
TypeError: Unable to get property 'Refresh' of undefined or null reference
Which suggests that the control[i] is null when called in the loop at this point here
for (var i in controls) {
controls[i].refresh();//error thrown here - suggests controls[i] is null
subGridNames += (" - " + controls[i].getName() + "\n");
}
However I can see that it isn't null (and has the method refresh as expected).
I can make it work by using setInterval
function waitAndThenRefresh(gridname) {
var grid = Xrm.Page.ui.controls.get(gridname);
var intervalId = setInterval(function () {
if (grid === null || grid._control === null || grid._control._element === null) {
return;
}
if (grid._control._element.readyState === 'complete') {
window.clearInterval(intervalId);
if (grid != null) {
grid.refresh();
}
}
}, 1000);
}
But that is pretty hideous, not to mention does not explain with the SDK call doesn't work as expected.
So I guess the question is: has anyone else seen this issue? Or can you replicate it on another instance? Am I missing something? There is nothing in the SDK that suggests you need to defer calling refresh until the inner control's readyState is complete?
The code block you are using,
for (var i in controls) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
should be replaced with the following:
for (var i in controls) {
i.refresh();
subGridNames += (" - " + i.getName() + "\n");
}
or:
for (var i = 0; i < controls.length; i++) {
controls[i].refresh();
subGridNames += (" - " + controls[i].getName() + "\n");
}
You are getting the exception because controls[i] is undefined in your case, i being the control (the element of the array controls).
I asked a CRM-buddy of mine. He said that the issue depends on the new refreshment Engine. According to him, it's sort of a bug but not really. If I got it right, the refresh has been reengineered to accommodate the new perpetual saving functionality.

Categories

Resources