Properly pass an element to React for Rendering - javascript

I have the following code to create and render a React element without using JSX:
function Weekday(props) {
return React.createElement('p', null, `Today is ${props.day}`);
}
let dayElem = React.createElement(Weekday, {day: 'Monday'});
ReactDOM.createRoot(document.getElementById('app')).render(dayElem);
This is based on a tutorial that I am following. As you can see, createElement() is being called twice above. I thought it was weird and decided to define dayElem like this:
let dayElem = Weekday({day: 'Monday'});
It still works and renders the content properly. Is there a particular reason why the tutorial did it the first way, instead of simply calling the function?
Are there any disadvantages of using the second method?
Thanks.

Related

changing element in ngOnInit not working when changing route, but is able to access element

I have an angular project with a router. In the ngOnInits for the components I want to dynamically set a a p tags value, and an img tags href. It works on inital load, but when i change routes the values dont change. The ngOnInit function is called, but the editing of the two elements does not work.
document.getElementById('discord-tag').innerHTML = username;
document.getElementById('profilePicture').setAttribute('src', image_url)
my code is simple.
i know the ngOnInit function is working because i put some console.log statements in there to test and they run each time i click on a route link.
In Angular we work with variables, manipulating the DOM directly should be the last resort, if there is no other way... BUT, usually there is an "Angular way" to handle things so that you don't need to manipulate the DOM directly. That being said, have variables in your component, which you bind to the template, so, however you get those values, assign them to variable, in OnInit, or the proper place you have them...
image_url!: string;
username!: string;
ngOnInit() {
// doing stuff, getting the values... then:
this.username = 'valueHere';
this.image_url = 'valueHere';
}
Then in template use these:
<img [src]="image_url" />
<p>{{username}}</p>
As mentioned in comment, these are basic things, so I really urge you to look into the tutorial on angular.io. It's a good tutorial and you will surely learn the basics there :) https://angular.io/tutorial
Try ngAfterViewInit() for changing 2 elements.

Instantiate WebComponent "easily"

I have created a simple Web Component to add in a parent (say "div#left" in this example). The component do nothing, except showing a text (it will be more elaborate later).
It's working if I do:
in html
<my-comp text="TEST"></my-comp>
in JS
document.getElementById("left").innerHTML += '<my-comp text="bar"></my-comp>';
or
var c = document.createElement("my-comp");
c.setAttribute("text", "buzz");
document.getElementById("left").appendChild(c);
But, I want something more "easy" to instantiate it (more "natural" for me...), via a method like
const gb = new MyComp({ text: "foo" });
gb.addInParent("#left")
or via a generic function (to instantiate any component), like:
const gb = new MyComp({ text: "foo" });
addInParent("#left", gb)
It may be simple, but I can't find how to implement the method/function addInParent... (all my research leads me to React or equivalent, which I don't use for this specific case)
Thank's in advance
I'm not sure if i got it right but you only want to change de inner part of the component to the received prop, right?
Have you tried slots?
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots
for example in your web component render method
<div>
<slot>Slotted text</slot>
</div>
and then in your page you call your component and pass the text like
<my-comp>My text here</my-comp>

bracket notation does not work with aframe

When using A-Frame, it not not possible to access component named with a dash, like "orbit-controls".
I am trying to access aframe component "orbit-controls". Link below:
aframe-orbit-controls component
since this component's minAzimuthAngle and maxAzimuthAngle is not working so I have to access its source to use script to change it. But when I tried to access it, I cannot use
var componentAngle = el.components['orbit-controls'];
to get the component and it returns undefined. When I log
var componentAngle = el.components
, it returns:
So how can I access this "orbit-controls"? I also tried
var getAngle = el.getAttribute('orbit-controls');
which returns
and these are only numbers and changing them wont change the real minAzimuthAngle. So I am wondering if there is a way to access the property showed in the first image? Very much appreciated.
Below is the code link.
try to access "orbit-controls" component
You should wait until the entity is fully loaded before grabbing this.el.components['orbit-controls']:
this.el.addEventListener('loaded', e => {
console.log(this.el.components['orbit-controls']
})
The azimuth component is added before orbit-controls so when the first one is being initialized, the latter might not be ready yet.
Fiddle here.

Making Vue.js detect changes to array using $set()

I'm having trouble updating an array that is displayed as a list. I'm trying to make Vue detect the changes using $set() (as explained in the documentation), but I can't make it work.
Here's my code:
this.choices = this.currentScene.choices;
for (i = 0; i < this.choices.length; i++) {
choice = this.currentScene.choices[i];
choice.parsedText = this.parseText(choice.text);
this.choices.$set(i, choice);
}
Vue still doesn't update the view. What am I doing wrong? Thanks in advance!
Edit: Yes, "this" refers to the Vue instance.
It would definitely be useful to have a JSfiddle of your code, but I'm going to take a crack anyways.
I'm not sure you need to use that function to update the array, since as the documentation points out, its only when you need to change the index of the item.
JavaScript has a built in function called .map that takes a callback function and returns a new array with the callback applied to each item.
For example, you could translate your function to this, assuming that .parseText is a method on the Vue class.
var self = this; // so that we can access the Vue class inside map
this.choices = this.currentScene.choices.map(function(choice) {
choice.parsedText = self.parseText(choice.text);
return choice;
});
And Vue should pick up those changes.
You could use a computed property for this, so you never have to manually update the array. Anytime choices changes you would see the change reflected in this.parsedChoices:
computed: {
parsedChoices: function(){
return this.currentScene.choices.map(function(choice) {
choice.parsedText = this.parseText(choice.text);
return choice;
}.bind(this)); // bind Vue class as value of `this` inside func
}
}

If() block changing the Meteor data received

OK. I am speechless. I encountered this weird behavior like two days ago and I can't really tell what is going on.
In my code I have:
character: Characters.find({
'user._id': Meteor.userId(),
'gameId': this.props.gameId
}).fetch(),
It is inside the getMeteorData function (I use Meteor with React), mixin [ReactMeteorData] is also present.
Now in the componentWillMount() function I have this piece of code. What I want to do is to check if there is a character inside created by this user and in this game.
componentDidMount: function() {
console.log(this.data.character);
}
It returns [Class] with the character I was looking for. Great! So now I add this piece of code and it looks like this:
componentDidMount: function() {
console.log(this.data.character);
if (this.data.character.length > 0) {
console.log('yay!');
} else {
console.log('nay...');
}
}
So that's a normal, unsuspicious if(). Guess what I get from that first console.log(): []. WHY? Why is it that this if is changing what I get from my DB?!
The problem was that subscriptions were not ready when I tried to use them. What I did is rewrite the way subscriptions are made. I moved it from the router (so no subscriptions there) to the component itself. Like this:
data = {}
subs = {}
subs.something = Meteor.subscribe("something", argument);
if (subs.something.ready()) {
data.something = Somethings.find({}).fetch();
// the same query I use in publish method but with .fetch()
// because otherwise Meteor throws a warning
}
This is the code that goes to the getMeteorData function. And then inside the render() I can use those subscriptions like this:
render: function() {
return(
<p>{this.data.something ? this.data.something.property : 'Loading...'}</p>
);
}
And then it works perfectly fine. I had rewritten all of my components to use this way of doing things and now I have NO problems with subscriptions whatsoever. It also feels more "componentish" and "reactish" as everything including subscriptions is included in the parent component and the relevant data is being passed to children via props. No need to look for code and subscription methods in the router.

Categories