JSX syntax error on PHPStorm - javascript

I'm trying to conditionally set a property on a collection of elements.
render: {
var buttons = [];
for (var i = 1; i <= this.props.totalWeeks; i++) {
buttons.push(
<button
onClick={ this.changeWeek.bind(this, i) }
disabled={ i === this.state.currWeek }>{ i }
</button>);
}
}
Everything works great in the browser. But PHPStorm (version 8.0.3) marks the expression { i === this.state.currWeek } as an error for wrong attribute value.
I've tried changing that with a function call, a variable, etc., but can't seem to make error go away. I've also tried to turn off that inspection rule on PHPStorm, but can't find the one setting that would turn that off.
QUESTION
How can I make that error go away in PHPStorm? If that's a bug, then how can I get rid of that by conditionally adding HTML attributes to a group of elements some other way?

1) If it's render of react (not your custom function), it should be "render() { return ; }" against your code
It's 100% syntax error, browser ignores it, because it should, if you use it in class definition body, syntax is next:
class Test {
objectExample: { some: "value" }
functionExample() { return someExecutionCode(); }
lambdaFunctionExample = () => { return someExecutionCode(); }
}
But you mix 1st and 2nd lines in same time, start as object definition, with body as a function, which are not fits to each other.
2) Your render function NOT return anything, it's making array, but not return it.

Related

Pass an object that has an optional property to a function that guarantee it will not be undefined but editor/compiler still think it can be undefined

function f1(
toolbox: {
tool1?: Tool1,
tool2?: Tool2,
}
) {
if (!toolbox.tool1) {
toolbox.tool1 = fetchTool1();
}
if (!toolbox.tool2) {
toolbox.tool2 = fetchTool2();
}
// Do something else
}
function f2(
toolbox: {
tool1?: Tool1,
tool2?: Tool2,
}
) {
f1(toolbox);
// tool1 and tool2 are no longer undefined.
const x = toolbox.tool1.value // Editor shows error, tool1 may be undefined.
}
The design above passes a toolbox object to different functions, so the program doesn't need to fetch the tools that are already fetched by other functions. The problem is, even if I know for sure toolbox.tool1 and toolbox.tool2 will not be undefined after calling f1, the editor still shows error.
I know I can use exclamation mark like const x = toolbox.tool1!.value, or maybe just turn off the warning. But I'm looking for a way that is more friendly to the default type checking.
I have tried let f1 return the toolbox that has no question mark in it, and call toolbox = f1(toolbox). It doesn't work, the line const x = toolbox.tool1.value still shows error.
You're looking for asserts.
f1 now looks like this:
function f1(
toolbox: {
tool1?: Tool1,
tool2?: Tool2,
}
): asserts toolbox is { tool1: Tool1; tool2: Tool2 } {
You can think of this as "changing" the type in the scope it was called:
f1(toolbox);
toolbox // now { tool1: Tool1; tool2: Tool2 }
const x = toolbox.tool1.value; // fine
Playground

Webpack plugin parser hook doesn't tap for expression

I'm writing a plugin for webpack for extracting values from MyObject.myProperty = 'myValue'; expressions, and my hook doesn't tap for my expression. Here is the example code:
var zzz = (function () {
function zzz() {
return this;
}
zzz.MY_VAR = "My value";
return zzz;
});
Here is how my code for the hook looks like:
parser.hooks.expression.for("zzz.MY_VAR").tap("MyPlugin", expr => {
console.log(expr);
}
I also tried:
parser.hooks.evaluate.for("AssignmentExpression").tap("MyPlugin", expr => {
console.log(expr);
}
Also without success.
I did some debugging, and find out that for some reason when JavascriptParser is calling getFreeInfoFromVariable() in getMemberExpressionInfo() it returns undefined. Because getVariableInfo() method return some scope details instead of VariableInfo instance or 'string'.
Am I missing something ? Is it possible to get value of the object's property via parser somehow ? Or maybe there is another way to do it ?

Check if property exists using React.js

I'm new to using react.js, and am trying to write a re-usable component that has an optional property passed to it. In the component, that optional property pulls data from a db using meteor, then I want to check if a property exists on the returned object (parent_task exists on task), and if exists, adds a link. This seems fairly simple, but I keep getting errors. Does anyone have any suggestions on what I might be missing? Is there a jsx gotcha that I'm missing?
<Header task={params.task_id} /> // rendering component with property
// Task List Header
Header = React.createClass({
mixins: [ReactMeteorData],
getMeteorData() {
var handle = Meteor.subscribe('tasks');
return {
taskLoading: ! handle.ready(),
task: Tasks.findOne({_id: this.props.task})
}
},
getParentTaskLink() {
if (!this.data.taskLoading) {
var current_task = this.data.task;
if (parent_task in current_task) { // or current_task.hasOwnProperty(parent_task)
console.log("parent_task exists!");
}
}
},
render() {
return (
<div className="bar bar-header bar-calm">
{this.getParentTaskLink()} // eventually return anchor element here
<h1 className="title">Hello World</h1>
</div>
)
}
});
what is the prop in question? how about
{this.props.propInQuestion ? link : null}
I figured this out. Apparently it was a syntax issue - you need to use a string when searching for properties in objects. The line below works:
if ('parent_task' in current_task)
For me works:
if ('myProperty' in this.props) {}
or
if (this.props.myProperty !== undefined) {}
or
if (this.props.hasOwnProperty('myProperty')) {}
Next condition will not work for number property, as 0 value will not work (such as for empty string):
if (this.props.MaxValue) {}
Check if a property exists using React.js
There are two options you can use. the && operator and If statement to check if the props exist.
Option 1 will check if the property exists then run the second part of the code. It works like an if without the if.
Option 1
this.props.property && this.props.property
Option 2
if(this.props.property){
this.props.property
}
This also works with function names.
You can use this also check to render components and tags.
This works for me
if(this.props.test === undefined){
console.log('props.test is not defined')
}
I suggest to try this elegant solution to check callback property on your component:
if(typeof this.props.onClickCallback === 'function') {
// Do stuff;
}
or applying destructuring:
const { onClickCallback } = this.props;
if(typeof onClickCallback === 'function') {
// Do stuff;
}
The most upvoted answer
props.propInQuestion ? 'a' : 'b'
Doesn't work if the prop is a boolean and you're trying to check for existence.
Based on How do I check if an object has a key in JavaScript? the fastest way is props.hasOwnProperty('propInQuestion'), with the caveat that this will not search the prototype chain.
In functional components, you can use like this.
if(props.myProperty){
//do something
}else{
//do something
}
if(props.hasOwnProperty('propertyName')){
//do something
} else {
//do something else
}
You need to return out of getParentTaskLink() with the link you need.
if (current_task.parent_task) {
return (link);
} else { return null; }

pure javascript onclick becomes undefined after assigning functions scope ends

It's been a while since I wrote Javascript without jQuery, so please bear with me. I'm assuming I'm just doing something silly. I have this function that converts link urls to an internal representation that I use with a router I wrote.
Templater.prototype.replace_links = function() {
this.links = document.getElementsByTagName("a");
for (i = 0; i < this.links.length; i++) {
if (!(this.links[i].getAttribute("href") === this.VOID && this.links[i].getAttribute(this.HREF))) {
this.links[i].setAttribute(this.HREF, this.links[i].getAttribute("href"));
this.links[i].setAttribute("href", this.VOID);
this.links[i].onClick = function(self, link) {
return function() { self.router.go(link.getAttribute(self.HREF)); };
}(this, this.links[i]);
}
}
}
This function is called the first time when Templater is initialized. The first time it works correctly. However, I run it a second time after I append some html into the body of the document. I run it again just in case that appended html has links in it too:
<body>
<!-- arbitrary new html is loaded in here -->
Login <!-- becomes Login correctly -->
Home <!-- becomes Home correctly -->
</body>
When I console.log(this.links[0], this.links[0].onClick) after the function has been run but still within a Templater function, I get the correct html and then undefined for the onClick event:
Discover undefined
When I log the same to values within the replace_links scope, I get what I'm expecting. I.e. the function is shown:
Discover function () { self.router.go(link.getAttribute(self.HREF)); }
I was playing around with it some more and tried this way and got the same kind of thing.
Templater.prototype.replace_links = function() {
this.links = document.getElementsByTagName("a");
for (i = 0; i < this.links.length; i++) {
if (!(this.links[i].getAttribute("href") === this.VOID && this.links[i].getAttribute(this.HREF))) {
(function(self, link) {
link.setAttribute(self.HREF, link.getAttribute("href"));
link.setAttribute("href", self.VOID);
link.onClick = function() { self.router.go(link.getAttribute(self.HREF)); };
})(this, this.links[i]);
}
}
}
I console.log after the replace_link scope ends like before and this time I still get:
Discover undefined
I'd really appreciate any help and/or suggestions! Please let me know if I'm missing anything helpful.
The key points here have been treated as minor details.
I append some html into the body of the document
and
this.links[i].onClick = function(self, link) {
My point is, if you alter innerHTML, which I assume is the way you "append some html into the body of the document," the browser will serialize the DOM objects into HTML, do the string concatenation, and then parse it again. This results in new objects which no longer have the expandos, such as onClick. onClick is a custom property; you probably meant onclick anyway.
However, some of your changes will be serialized and parsed successfully, namely the setAttribute operations. Thus, when you run replace_links after the HTML appending, the
if (!(this.links[i].getAttribute("href") === this.VOID && this.links[i].getAttribute(this.HREF)))
check will treat the link as already replaced and not assign the onClick again.
Here's a fiddle that shows this in action. http://jsfiddle.net/k9d7b2ds/
UPDATE: Made some additional changes. The onclick event's default this object is always referencing the window object. You need to pass over the closure.
Check sample code here:
http://jsfiddle.net/y0443fz6/
Templater.prototype.replace_links = function() {
var that = this;
this.links = document.getElementsByTagName("a");
for (i = 0; i < this.links.length; i++) {
if (!(this.links[i].getAttribute("href") === this.VOID && this.links[i].getAttribute(this.HREF))) {
this.links[i].setAttribute(this.HREF, this.links[i].getAttribute("href"));
this.links[i].setAttribute("href", this.VOID);
this.links[i].onclick = function(self, link) {
return function() {
self.router.go(link.getAttribute(self.HREF));
};
}(that, this.links[i]);
}
console.log(this.links[i], this.links[i].onclick);
}
}
hope that helps. gl

JSHint error Don't make functions within a loop

I'm running some code through JSHint and I keep getting the following error:
Don't make functions within a loop.
I tried turning off the warning for 'About functions inside loops' off which does nothing to stop the error from being reported. I have decided to refactor the code, using JSHint's suggestions here, http://www.jshint.com/options/ but I'm still getting the error. I was hoping that somebody could help me to refactor this code slightly so it will pass. Here's a copy of the function:
function setSounds(parent) {
var i,
l;
parent.getElements('.sound').each(function (elem) {
var soundEvents = [];
if (elem.get('fk_click_sound')) {
soundEvents.push('click');
}
if (elem.get('fk_mouseover_sound')) {
soundEvents.push('mouseenter');
}
if (soundEvents.length !== 0) {
for (i = 0, l = soundEvents.length; i < l; i += 1) {
elem.addEvent(soundEvents[i], (function () {
return function (e) {
FKSoundAIR(FKSoundStd[this.get('fk_' + e.type + '_sound')]);
};
})(elem), false);
}
}
});
}
I'm using MooTools. The purpose of this function is to pass a parent element and then apply sound event to all of the children with the class 'sound.' I'm using custom HTML attributes, such as 'fk_click_sound' to feed additional information to the function. I picked up this method of assigning a function within a loop from http://blog.jbrantly.com/2010/04/creating-javascript-function-inside.html.
Any suggestions or resources that you can point me to would be great. Thanks!
You can try something like this:
function make_handler(div_id) {
return function () {
alert(div_id);
}
}
for (i ...) {
div_id = divs[i].id;
divs[i].onclick = make_handler(div_id);
}
You could create the function outside, assign it to a var and use it in your call to addEvent.
As it turns out JS Hint had a bug re: the warning for Looping inside of a function, which they fixed here. Now that this is fixed, this issue is resolved.

Categories

Resources