React: no <span> around text nodes - reactjs

According to React 15.0 release notes, React is no longer supposed to emit <span> tags around text nodes. I tried that using jsbin and script
const Span = () => (<span>a</span>)
const text = 'text'
const Text = () => (<span>{text}</span>)
const Div = (<div>
<Span/><Span/><Span/><Text/>
</div>)
ReactDOM.render(Div, document.querySelector('#target'))
is rendered as
<div data-reactroot="">
<span>a</span>
<span>a</span>
<span>a</span>
<span>text</span>
</div>
So it doesn't work. I'd expect string a to be rendered without surrounding <span> tags. How is this feature supposed to work? Is it necessary to enable it in some way?

The feature is used when writing something like this:
<div>{'a'}{'b'}</div>
"a" and "b" was surrounded by tags and the dom was kinda full with this tags when using this multiple times in different components.
With 0.14.8 this was rendered as:
<div data-reactid=".0">
<span data-reactid=".0.0">a</span>
<span data-reactid=".0.1">b</span>
</div>
With 15.0 this is rendered as:
<div data-reactroot>
<!-- react-text: 2 -->a<!-- /react-text -->
<!-- react-text: 3 -->b<!-- /react-text -->
</div>
This is explained in https://github.com/facebook/react/pull/5753 and can be tested with something like https://codesandbox.io/s/N1znXxXL.

Related

How can we add multiple classes to the `ReactMarkdown` while rendering

I my react app, I am using react markdown for rendering the blog content. How can we add multiple classes to the ReactMarkdown. At the moment I have used dataArea class alone, but i would need to use below classes for styling purpose. Could someone please advise ?
.blogImageSection
.dataArea
.dataDate
.tags
.readmoreLink
.dataArea p
. views
csb link for reference : https://codesandbox.io/s/great-bardeen-9lsog5?file=/src/App.js
// react markdown usage:
{ popularResults.map (({id, blogdetails, tags, createdAt }) => (
<ReactMarkdown className='dataArea' remarkPlugins={[remarkGfm]}>{blogdetails}
</ReactMarkdown>
))}
This is the normal blog where I have used the above classes without using react markdown
<a key={id} href="my url">
<div key={id} className='blogImageSection'>
<img alt="id" src={photo} />
<div key={id} className='dataArea'>
<span key={id} className='dataDate'>{date}</span>
<span className='tags'>cypress</span>
<h3>{heading}</h3>
<p>
Best heading added here.
The most relevant data added here.
Greatest of all time. Print the whole text here.
Ideas are always usefull....
</p>
<a href="_blank" className="readmoreLink">
Read more →
</a>
<span className='views'>
{topViews > 999 ? (topViews / 1000).toFixed(2) + "K" : topViews}
</span>
</div>
</div>
</a>
you can add all classes like this:
className='dataArea blogImageSection dataArea dataDate tags readmoreLink dataArea views'

How to use useRef to toggle between images

Given an image gallery, where the user can click an image and the selected image will be shown in the gallery below it, how can I use useRef to replace the image in the gallery div with the selected image on click? The idea is that the images will be populating the gallery at the top from an array, so each image will presumably have the useRef applied to it?
HTML
<div class="wrapper">
<div class="row">
<div class="column">
<img src="imageurl" alt="water" style="width:100%" onclick="myFunction(this);">
</div>
<div class="column">
<img src="imageurl2" alt="tree" style="width:100%" onclick="myFunction(this);">
</div>
<div class="column">
<img src="imageurl3" alt="snow" style="width:100%" onClick="myFunction(this);">
</div>
<div class="column">
<img src="imageurl4" alt="mountain" style="width:100%" onclick="myFunction(this);">
</div>
<div class="column">
<img src="imageurl5" alt="tree2" style="width:100%" onclick="myFunction(this);">
</div>
</div>
<div class="container">
<span onclick="this.parentElement.style.display='none'" class="closebtn">×</span>
<img id="expandedImg" style="width:100%">
<div id="imgtext"></div>
</div>
</div>
Function to toggle large image visibility
const myFunction = imgs => {
const imageRef = useRef();
var expandImg = document.getElementById("expandedImg");
var imgText = document.getElementById("imgtext");
expandImg.src = imgs.src;
imgText.innerHTML = imgs.alt;
expandImg.parentElement.style.display = "block";
}
The current state can be seen here: jsFiddle
As the React Docs state: Don’t Overuse Refs
Your code snippet is not what refs should be used for. In React, you should make things interactive via state changes, not by fiddling with the DOM, React is designed to do that for you.
However from that jsfiddle, it looks like you aren't even using React? I am unsure why you are using useRef at all?
UPDATE: Code fix
By using function to define your function (instead of an arrow function), it gets hoisted so your HTML elements can pick it up, and the getElementById method gets you the element reference you need.
Just replace all your js with:
var expandImg = document.getElementById("expandedImg");
var imgText = document.getElementById("imgtext");
function myFunction(imgs) {
expandImg.src = imgs.src;
imgText.innerHTML = imgs.alt;
expandImg.parentElement.style.display = "block";
}
...and your jsfiddle works.

React: microdata typeScope being pased weirdly

I'm trying to set microdata to a p element contained in a parent component. When I set itemScope="" in the parent I don't get it in the p element in the dom, but if I set itemScope alone, it works as expected, although this means itemScope={true} as per React rules. ItemScope is a boolean attribute so as per HTML specs it should be empty string or canonical value when you want it to be considered true. What am I missing?
See fiddle:
https://jsfiddle.net/rv9085ob/
<!-- html -->
<div id="app"></div>
// js
const SimpleComp = (props) => <p {...props}>ItemScope is [{JSON.stringify(props.itemScope)}]</p>;
const fragment = <div>
<SimpleComp itemScope="" />
<SimpleComp itemScope />
<SimpleComp itemScope={true} />
</div>;
ReactDOM.render(fragment, document.querySelector("#app"))
Results in:
<div>
<p>ItemScope is [""]</p>
<p itemscope="">ItemScope is [true]</p>
<p itemscope="">ItemScope is [true]</p>
</div>
Please refer to this issue in the React Github repository. https://github.com/facebook/react/issues/13400
There is a PR open for this here, it seems to be ongoing - https://github.com/facebook/react/pull/13404

AngularJS- How to handle each button created by ng-repeat

I am new to AngularJS.
I have created <li> to which I used ng-repeat.
<li> contains images and buttons like like, comment and share which is inside <li> and created by ng-repeat.
I have made function which will replace empty like button to filled like button (By changing background image of button).
But problem is this trigger applies to only first like button and other buttons does not change.
How can I fix this?
Code:
HTML:
<html>
<body>
<ul>
<li ng-repeat="media in images"><div class="imgsub">
<label class="usrlabel">Username</label>
<div class="imagedb">
<input type="hidden" value="{{media.id}}">
<img ng-src="{{ media.imgurl }}" alt="Your photos"/>
</div>
<!-- <br><hr width="50%"> -->
<div class="desc">
<p>{{media.alt}}</p>
<input type="button" class="likebutton" id="likeb" ng-click="like(media.id)" ng-dblclick="dislike(media .id)"/>
<input type="button" class="commentbutton"/>
<input type="button" class="sharebutton"/>
</div>
</div> <br>
</li><br><br><br>
</ul>
</body>
</html>
JS:
$scope.like = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-filled.png)";
alert(imgid);
}
$scope.dislike = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-empty.png)";
}
Thanks for help & suggestions :)
The id for each button should be unique but in your case, it's the same for all buttons ('likeb').
You can set the value of the attribute 'id' for each button dynamically by using '$index' and passing '$index' to the functions as follows:
<input type="button" class="likebutton" id="{{$index}}" ng-click="like($index)" ng-dblclick="dislike($index)"/>
Then in your controller, you can use the functions with the passed value.
For example,
$scope.like = function(index)
{
document.
getElementById(index).
style.backgroundImage = "url(src/assets/like-filled.png)";
}
Another good alternative in your case would be to use the directive ngClass.
use 2 css class for styling liked and disliked state, and then put the class conditionally with ng-class instead of DOM handling. and if you really want to perform a DOM operation (I will not recommend) then you can pass $event and style $event.currentTarget in order to perform some operation on that DOM object.

toggle extra detail for a record inside an ngRepeat

I'm working on a project where the client has supplied a pile of html where I need to plugin the data from our database and have hit a problem that I'm finding difficult to solve....
So first problem is with routing
<div ng-repeat="class in vm.classes">
<div class="class-overview">
<a href="#">
<span class="class-title">{{class.description}}</span>
... more stuff here
</a>
</div>
<div class="class-information collapse">
<div class="full-width">
{{class.longDescription}}
</div>
</div>
</div>
he has supplied some javascript to handle the click on class-overview
$('.class-overview a').on('click',function(e) {
e.preventDefault();
});
$('.class-overview').on('click',function() {
$('.class-overview.active').removeClass('active').next('.class-information').collapse('hide');
$(this).addClass('active').next('.class-information').collapse('show');//.css('top',offset).collapse('show');
});
and i have a line like this in my state provider
// default route
$urlrouterProvider.otherwise("/")
So the problem is that the ui-router handles the click and sends me back to the home page.
The ideal solution is to leave as much of his markup intact, so can anyone tell me how I stop ui-router handling the click?
or failing that, how I might use ng-click and ng-show to get the same effect, i.e. hiding and showing the class-information div...
If I understand well your question, you want to display the .class-information div when you click on the .class-overview element.
That can be done by using a variable in a ng-show like this:
<div ng-repeat="class in vm.classes">
<div class="class-overview">
<a href="#" ng-click="display = !display">
<span class="class-title">{{class.description}}</span>
... more stuff here
</a>
</div>
<div class="class-information" ng-show="display">
<div class="full-width">
{{class.longDescription}}
</div>
</div>
</div>
The display variable will be falsy when you land on the page, therefore the ng-click will be executed, this variable will be set to true.
I see that you are using a collapse class to hide the content if it is collapsed. Then you could use angular ng-class to put the collapse class when the display variable is false. Your div.class-information would look like this:
<div class="class-information" ng-class="{collapse: !display}">
<div class="full-width">
{{class.longDescription}}
</div>
</div>

Resources