react-empty
<div data-reactroot>
<!-- react-empty: 3 -->
<!-- react-empty: 26 -->
</div>
What is this node ? Why can it render to a React Component ? How to do like this?
This is actually part of React's internal support for things like null:
// A perfectly valid component
() => null
// Also a perfectly valid component
const MyComponent = React.createClass({
render() {
if (this.props.hidden) return null;
return <p>My component implementation</p>;
}
});
Note that with React >= 16, you won't see <!-- react-empty: X --> anymore
Look at this part of React code which is create this:
var nodeValue = ' react-empty: ' + this._domID + ' ';
if (transaction.useCreateElement) {
var ownerDocument = hostContainerInfo._ownerDocument;
var node = ownerDocument.createComment(nodeValue);
ReactDOMComponentTree.precacheNode(this, node);
return DOMLazyTree(node);
} else {
if (transaction.renderToStaticMarkup) {
// Normally we'd insert a comment node, but since this is a situation
// where React won't take over (static pages), we can simply return
// nothing.
return '';
}
return '<!--' + nodeValue + '-->';
}
},
So basically if your component return null, it will create a comment which showing this element is empty, but React take care of that for you by putting a comment there like <!-- react-empty: 3 --> all JavaScript frameworks try to get use of comment in the DOM, to show they handle the code, similar one is ng-if in angular for example...
Related
View (HTML)
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<h2><span data-bind="text: fullName"> </span>!</h2>
nameConcat.js (KnockoutJS)
var ViewModel = function(first, last) {
this.firstName = ko.observable(first);
this.lastName = ko.observable(last);
this.fullName = ko.pureComputed(function() {
return this.firstName() + " " + this.lastName();
}, this);
};
ko.applyBindings(new ViewModel("Tom", "Haykens"));
React Component
class NameConcat extends React.Component {
render() {
return (
???
);
}
}
I am a ReactJS newbie. How do I display knockoutJS application pages from ReactJS components ? Rewriting KnockoutJS pages in ReactJS is not an option.
Thanks in advance.
In my project the skeleton was designed in Durandel ,part of the reason I could not use the option of rewriting in React .
So here is what I had to use :
Case 1) - Want to bind a data in KO way
public observableVariable = Observable();
public binding() { // durandle lifecycle hook // observable declared with the class
reactDom.render(<span data-bind={`text: observableVariable `}></span>, document.getElementById('reactRoot'));
}
Case 2) - Want to bind an already KO page to React and leave the DOM to be updated at real DOM .
public observableVariable = Observable();
public binding() { // durandle lifecycle hook // observable declared with the class
reactDom.render(<div data-bind={`compose: { model: '-- index page where the knockout binding is written --',activationData: { --Observable parameter--: --Observable data--} }`}></div>, document.getElementById('reactRoot'));
}
Case 3) - Template Binding
// declare all the observable at the top
// All These component can be sent anywhere from the react composed child
<div dangerouslySetInnerHTML={{
__html: `<!--ko widget: {
kind: '--index--',
name: 'sample comp',
// write all the observable dependencies here ,
id: 'sample Id'
} -->
<!-- /ko -->`}} />
Case 4) If you want to load regular react component using observable : I mean if you want some data maintained in observable to use in react.
Have an tracking object and keep the data in sync using Observable subscribe :
{
self reactPropValue;
self.selectedVals.subscribe(function (newValue: any) {
let val = ko.toJSON(newValue);
reactPropValue= ko.toJSON(selectedVals());
});
}
Now you can pass this into react component as a prop and each time the observable changes the subscribe will make sure to get a new value , dont forget to wrap your reactDom in side an function and call on subscribe ,because by design it wont trigger a reload .
If you are not in durandel you might need to add the ko.applybinding yourself otherwise its fine .
Look out for the error message in the console window if you get any , There could be some .
Sorry if my answer is not properly formatted .
I am having an issue with a project I'm working on. I am using an API to return an array of platforms a video game is on. The array is returning the correct results, however I am having trouble displaying those values in my HTML. The result is just showing undefined.
// Renders platform information for each game
const renderPlatformInfo = function (platformResult) {
const gamePlatform = [];
for (let i = 0; i <= `${platformResult.length - 1}`; i++) {
let getPlatforms = gamePlatform.push(platformResult[i].name);
}
gamePlatform.forEach(function (platformItem) {
$('.platforms').append(`<li>${platformItem}</li>`)
});
console.log(gamePlatform);
};
// Renders game information for the searched game
const renderGameInfo = function (gameInfoResult) {
return `<div class="js-game-data row">
<h2 class="game-name col-12">${gameInfoResult.name}</h2>
<img src="${gameInfoResult.image.medium_url}" class="game-image col-4" alt="Box art for ${gameInfoResult.name}">
<ul class="platforms col-6">
<h3 class="col-12">Original release date:</h3>${gameInfoResult.original_release_date}
<h3>Platforms:</h3>
${renderPlatformInfo(gameInfoResult.platforms)}
</ul>
<p class="game-description col-6">${gameInfoResult.deck} <br> <br> <span class="game-details col-12"><b>For more details about the game: Click Here</b></span></p>
</div>
`;
}
renderPlatformInfo can't append children to a DOM element that doesn't exist yet. The UL it's trying to select isn't rendered at the time you're trying to append. Additionally, since renderPlatformInfo doesn't return anything, it will always evaluate to undefined inside a template literal. If you return an HTML string inside renderPlatformInfo, your code should work. Try something like:
let str = '';
gamePlatform.forEach(function(platformItem){
str += `<li>${platformItem}</li>`;
});
return str;
Should renderPlatformInfo return something. Are you missing the return there?
I am trying to analyse some html code and break it into an array of objects.
Here is some example html code:
<slide data-time=5>
<div class="cds-block-title">Master Calendar</div>
<div class="cds-block-content">iframe to master calendar</div>
</slide>
<slide data-time=5>
<div class="cds-block-title">Weather</div>
<div class="cds-block-content">iframe to master Weather App</div>
</slide>
My goal is to break it down into an object similar to this:
[
{
"html":"<slide.....</slide>",
"time":"5",
"title":"Master Calendar",
"content":"iframe...."
},
{
"html":"<slide.....</slide>",
"time":"5",
"title":"Master Calendar",
"content":"iframe...."
}
]
I have tried a few different approaches.
Using Regex (This worked in my test, but not when I put it in production, the .match stopped working as expected, I also read a few posts stating that using regex to parse html code is not the best approach):
function splitSlidesHtml(html){
var html = '<slide data-time="5"><div class="cds-block-title">Activities & Sports</div><div class="cds-block-content">content</div></slide><slide data-time="5"><div class="cds-block-title">weather</div><div class="cds-block-content">content</div></slide>"';
var slides = html.match(/<slide.*?>(.*?)<\/slide>/g);
var slidesA = [];
if (!slides) {
slidesA.push({"html":html});
} else {
for (i in slides){
var c = {};
c.html = slides[i];
c.time = slides[i].match(/(data-time=)(.*?)>/)[2].replace(/['"]+/g, ''); // extract the time, and replace any quotes that might be around it
c.title = slides[i].match(/<div class="cds-block-title">(.*?)<\/div>/)[1];
c.content = slides[i].match(/<div class="cds-block-content">(.*?)<\/div>/)[1];
slidesA.push(c);
}
}
return slidesA;
} // end splitSlidesHtml
I have also tried using jQuery, which kind-of works, but I don't know enough about parseHTML to know how to make sure it breaks at the different slides.
var slides = $.parseHTML(html);
console.log(slides);
console.log(slides[0].innerHTML);
console.log(slides[0].outerHTML);
You can use $.parseHTML() to convert your HTML string into an array of DOM nodes and then loop over the nodes to grab the information you need. .map() is a good use in this case as you are mapping each node to something else.
var html = '<slide data-time=5>\
<div class="cds-block-title">Master Calendar</div>\
<div class="cds-block-content">iframe to master calendar</div>\
</slide>\
<slide data-time=5>\
<div class="cds-block-title">Weather</div>\
<div class="cds-block-content">iframe to master Weather App</div>\
</slide>';
var slides = $($.parseHTML(html)).map(function () {
return {
// store the HTML
html: this.outerHTML,
// store the data-time attribute
time: this.dataset.time,
// store the title
title: $('.cds-block-title', this).text(),
// store the content
content: $('.cds-block-content', this).text(),
};
}).get();
console.log(slides);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
This is what I finally came up with. I had trouble with map working to get the time correctly.
var html = sheetData['values'][prop]['html'];
var parsed = $.parseHTML(html);
var isSlide = true;
for (n in parsed){
var cur = parsed[n];
if (cur.nodeName == "SLIDE"){
var curSlide = {
html: cur.outerHTML, // store the HTML
time: cur.dataset.time, // store the data-time attribute
title: $('.cds-block-title', cur).html(), // store the title
content: $('.cds-block-content', cur).html(), // store the content
};
} else {
isSlide = false;
}
}
I have a ReactClass with name Alert. Its render method returns a div with class alert alert-success or alert alert-error according to the type passed while creating element. I just want to know how to add class based on the type of alert element.
Here is my attempt:
var Alert = ReactClass({
render: function() {
return <div className="alert {this.props.type}">{this.props.message}</div>
}
});
var successAlert = React.createElement(Alert, {
type: 'alert-success'
message: 'Information saved successfully!!'
});
When JSX Template is compiled this.props.type is not converted to the class passed to element. How to achieve this ?
Looks like I have found answer to my question. We can simply do something like this:
var Alert = ReactClass({
render: function() {
return <div className={"alert " + this.props.type}>{this.props.message}</div>
}
});
Just put your classes inside Template evaluators { } in this case. Create your class string based on your props and states.
Hope this is helpful to others.
One way to accomplish this is to have a string which will contain all of your classes and then set it to the Component's className:
var Alert = ReactClass({
var yourClassName = 'alert ';
// Add any additional class names
yourClassName += this.props.type + ' ';
render: function() {
return <div className={yourClassName}>{this.props.message}</div>
}
});
or alternatively you can store your class names in an array and convert it to a class friendly string when you're ready to use it:
var Alert = ReactClass({
var yourClassArray = [];
// Add any additional class names
yourClassArray.push('alert');
yourClassArray.push(this.props.type);
var classString = yourClassArray.join(' ');
render: function() {
return <div className={classString}>{this.props.message}</div>
}
});
Take a look at the classnames package. You can do stuff like this:
className={classNames('alert', `alert-${type}`)}
or
className={classNames({
'alert': true,
'alert-success': success,
'alert-error': error
})
You can use JavaScript template literals
var Alert = ReactClass({
render: function() {
return <div className={`alert ${this.props.type}`}>{this.props.message}</div>
}
});
Your code can be written in following way:
const Alert = ({type, message}) =>
<div className={`alert ${type}`}>{message}</div>
Write in code
className={`form-control-sm d-inline per_player ${"per_player_b_" + index + "_score"}`}
and You will get
Is it possible to pass HTML tags as properties and then render in React.js
For example ES2015 syntax:
I add the property as a string with HTML tags:
renderItems(posts) {
var groupDate = this.props.item.date.toUpperCase();
var listCol = '<h4>' + groupDate.toString() + '</h4>';
return (<ViewList list={posts} postCol1={listCol}/>);
}
And in my ViewList component I have:
<div className="col-md-9">{this.props.postCol1}</div>
This is rendered as :
<h4>JANUARY 28TH, 2016</h4>
How do I get react to render the date excluding the HTML tags?
Different views uses this component and tags may be different explaining why I would like to include the tag.
This actually worked:
renderItems(posts) {
var groupDate = this.props.item.date.toUpperCase();
return (<ViewList list={posts} postCol1={<h4>{groupDate.toString()}</h4>}/>);
}
Take the <h4> tags out of the listCol string. Your ViewList component should render them:
<div className="col-md-9">
<h4>
{this.props.postCol1}
</h4>
</div>