Is there a way to have line breaks in text without using dangerouslySetInnerHTML? - reactjs

I need to replace \n to <br>. But it is taking this as in text.
How can I do that without using dangerouslySetInnerHTML?

Insert the text as you normally would, and fix the line breaks with CSS:
white-space: pre-wrap;
Don't use dangerouslySetInnerHTML unless you really have to.

var yourNewValueWithBr = yourOldValue.replace(/\n/g,"<br />");
After replacing this text, you will need to use dangerouslySetInnerHTML to render it as HTML.

This solution replaces \n to <br> and works without dangerouslySetInnerHTML:
render: function() {
var lines = this.props.text.split("\\n").map(function(line, n){
return (n == 0) ? [line] : [<br />, line];
});
return <div>{lines}</div>;
}
But if you need HTML formatting, and you're sure that your text is safe from XSS, I would recommend to stick with dangerouslySetInnerHTML and a regex replace like Chris Hawkes said.

You could use style={{whiteSpace: 'pre-wrap'}} for the wrapping div.
Now you will break line without dangerouslySetInnerHTML and <BR>
You can check browser compatibility over here: CSS SPEC

Related

Display HTML on React

I have a React rich text editor which saves long description state as HTML text. I am trying to display the long description on product pages. How do I parse it for it is displaying the HTML text rather than converting it.
It's displaying like this rather than parsing and converting the HTML
<p>hahahah baba is yellow <strong>kkkk very yellow</strong></p><p><strong>ichoo </strong></p>
You can assign this html to a variable and print by using the dangerouslySetInnerHTML prop.
eg
const html = '<p>hahahah baba is yellow <strong>kkkk very yellow</strong></p><p><strong>ichoo </strong></p>';
<div dangerouslySetInnerHTML={{__html:html}}></div>
dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack. So, you can set HTML directly from React, but you have to type out dangerouslySetInnerHTML and pass an object with a __html key, to remind yourself that it’s dangerous.
function createMarkup() {
return {__html: '<p>content...</p>'};
}
function MyComponent() {
return <div dangerouslySetInnerHTML={createMarkup()} />;
}
Example snippet:
https://codesandbox.io/s/stoic-matan-kzzydv?file=/src/App.js
You can use dangerouslySetInnerHTML as mentioned in React docs
I use react-render-html in my projects.
A sample code will look like this
import renderHTML from 'react-render-html';
renderHTML("<a class='github' href='https://github.com'><b>GitHub</b></a>")

Appending a prop to an already existing attribute inline

Is there a way to append a property from this.props to an HTML element's attribute that already exists, and to do it inline (in the name of code-simplicity), without any variables/addons?
Something like this (but obviously this one and few other ways that I tried to append didn't work for me):
render() {
return (
<div className="entity" id="ent"+{this.props.index}>bla</div>
);
}
I do know that I could declare a variable before, append the prop to it and then use it as the attribute, but I have many lines like this and it will make my code bigger than I wanted it to be.
Thanks.
You can concatenate attributes as you usually do with strings:
<div className="entity" id={"ent" + this.props.index}>bla</div>
or (es6 syntax)
<div className="entity" id={`ent${this.props.index}`}>bla</div>
id={"ent" + this.props.index}
Or using interpolation instead of string concatenation.
id={`ent${this.props.index}`}

How to test text-overflow element

when the text attribute is set to
text-overflow: ellipsis;
the overflowed text will be displayed as "XX..." (see screenshot for more )
how can I find the overflowed text/element in webdriver?
thanks in advance
Screenshot of Overflowed text
Probably the easiest/best way to do this is to use the JS innerText property, e.g.
driver.findElement(lcoator).getAttribute("innerText");
If I remember correctly, some browsers use textContent instead.
driver.findElement(lcoator).getAttribute("textContent");
This should get you the full text inside that element.
You could also pull innerHTML and parse it (if needed) or remove the text-overflow style from the element but these are harder/more complicated.
In case you have jQuery available in your project, you can write your own selector:
$.expr[':'].truncated = function (e) {
// you *might* want to check if css property "text-overflow"
// is set to "ellipsis" as well, to filter other truncations:
return e.offsetWidth < e.scrollWidth;
};
and go from there:
items = $('.your-selector:truncated');
(heavily based on the answers here)

ng-bind-html with ng-sanitize' linky output tags as strings

If I try to use both ng-sanitize's linky filter with ng-bind-html directive, it will transform initial string
Well, <b>this is bold</b>, but this should become link http://www.example.com Lets test it!
to one having link transformed to html link, but not having bold text - it will be outputed as text having tags in it.
Here's [DEMO]
My question is how do I get in result both bold text and normal html link if initialy I have just as string having some text surrounded by tags and text that looks like a link??
Plunkr Demo
You could write a custom filter to do the work of linky and put the tags back in... (this probably isn't super robust and I'm not the best at regexes, but if it works for everything you need it to, then it gets the job done.)
module.filter('linkyWithHtml', function($filter) {
return function(value) {
var linked = $filter('linky')(value);
var replaced = linked.replace(/\>/g, '>').replace(/\</g, '<');
return replaced;
};
});
Usage:
<div ng-bind-html="expr | linkyWithHtml"></div>

empty ng-src doesn't update image

I am using the ng-src directive in order to avoid the browser to request the image before Angular evaluate the expression.
ng-src={{image}} will update the src attribute of the image if the expression "image" change.
I misunderstand why the ng-src directive doesn't update the path of the image if the expression ("myImage.png") become empty ("").
When the expression become empty, the ng-src attribute become empty but the src attribute still the last known src. So it doesn't update the image. Why the src attribute isn't updated (to an empty src) so that the image "disappear".
Here is a plunker
Thanks
The answer to this is in the Angular code. It's not a bug, it's just the behavior they decided they wanted. Starting on line 13895, you can see this directive code:
forEach(['src', 'srcset', 'href'], function(attrName) {
var normalized = directiveNormalize('ng-' + attrName);
ngAttributeAliasDirectives[normalized] = function() {
return {
priority: 99, // it needs to run after the attributes are interpolated
link: function(scope, element, attr) {
attr.$observe(normalized, function(value) {
if (!value)
return;
attr.$set(attrName, value);
if (msie) element.prop(attrName, attr[attrName]);
});
}
};
};
});
The key is in:
if (!value) return;
So as you can see, if you change the ng-src expression to an empty string, this will never change the actual src value. You can get around this doing something MadScone suggested.
MadScone's suggestion is a cool idea, but it didn't work for me in all browsers. I ended up just showing the element only when the src isn't empty:
<img ng-show="theImage!==''" ng-src="{{theImage}}">
This seems like the safest option to me after reading through the thread that MadScone referenced (here). As a number of people pointed out there, the accepted answer doesn't work in all browsers and has some other issues that could arise. Simply hiding the element avoids all that.
Update:
As enpenax pointed out in the comments, the !=='' in the ng-show is totally unnecessary. Here's the cleaner version:
<img ng-show="theImage" ng-src="{{theImage}}">
Update (April 2015)
See developering's answer, apparently this method I suggested originally may not work in all browsers.
Original (February 2014)
I'm not fully sure why that's happening, but here's a way of solving it anyway. Add this function to your controller:
$scope.getImage = function(src) {
if (src !== "") {
return src;
} else {
return "//:0";
}
};
The "blank" image will get a source of //:0 which won't cause a missing image icon to appear (see the top answer on this thread).
Then you can set your source using:
<img ng-src="{{getImage(superImage)}}" />
EDIT:
Actually, it would be easier to change your button click to this:
<button ng-click="superImage = '//:0'">Remove superImage</button>
Then there's no need for the function. Although I think the function method is better.
Another short way of solving it:
<img ng-src="{{image?image:' '}}" />
fix it by set value = " ";
with whitespace.
I also add the following css to make sure it's not displayed.
img[src="_"]
display none !important
the real reason has been discussed here: https://github.com/angular/angular.js/issues/1218
ng-hide and ng-show can help you solve it
<img ng-src="{{Image}}" ng-hide="Image == null" ng-show="Image != null" ng-click="ChooseImage()" width="100%" />
$scope.Image = null;
or
<img ng-src="{{Image}}" ng-hide="Image === ''" ng-show="Image !== ''" ng-click="ChooseImage()" width="100%" />
$scope.Image = '';
<img data-ng-src="{{image || 'http://www.1x1px.me/FFFFFF-0.png'}}" data-ng-model="image">
You can choose any 1x1px image that suitable to your website and replace http://www.1x1px.me/FFFFFF-0.png of your own. For my website I use available image on http://www.1x1px.me.
P/S: No need to worry about the original src attribute of img tag because it's not affected to image model
A possible workaround to empty ng-src can be found here.
<img ng-src="{{image || '//:0' }}" />
Detailed explanation to use //:0 can be found from this answer.
To summarize:
It adopts the current protocol, omits the hostname and sets the port to zero, which is invalid and should be killed by the network layer.
Also instead of emptying ng-src, if you have a default image source then you can simply set the ng-src to that default src when ng-src have to be empty.
<img src="{{superImage}}" />
This works as expected
Edit:
Other work arround,may be you could have used and empty string.
ng-click="superImage = ' '
to make it empty. It does not trigger 404

Resources