I want to render some music data. I am saving the data i get back from an axios request into
an object called dailyPlaylist and destructure the values i need.
Since the artists and the name take a lot of space, i want to do a line break.
The artists come back as an array, so i could do:
artists: track.artists.slice(0, 5).map(artist => <p>{artist.name}</p>)
this works perfectly fine.
But now I am trying to do a line break also on the "name" property since some of the names are really long.
Is there an option to set a line break after a certain amount of characters?? I tried many methods I would use in vanilla JS but nothing worked.
For example i want to change the long name:
Dreamers (Music from the FIFA World Cup)
to:
Dreamers (Music from the <br>
FIFA World Cup)
or something like that.
My code so far:
const dailyPlaylist = {
tracks: response.data.tracks.items.map(({ track }) => ({
key: track.id,
name: track.album.name,
artists: track.artists.slice(0, 5).map(artist => <p>{artist.name}</p>), // line break between artists
image: track.album.images[1].url
}))
}
Thanks in advance
Unless there is a good reason why you want to achieve this using Javascript, I would do it with CSS instead.
Limit the width of the div or span containing the title. You could use max-width for example.
Something like this:
<span style={{maxWidth:100}} >
<p>{artist.name}</p>
</span>
Related
I am currently working on a page using NextJs and TailwindCss. The user has the ability of loading an image locally and setting the number of pieces horiz/vert (rows/cols) that they wish the image to be split in. To properly display this, I need to set the grid to the proper number of columns in the parent element.
I have an API I call locally that uses sharp to perform the split and calculate the width and height and I sort the images in my array so that they are in order since it is async. I then also generate a dynamic class string that just populates the proper number of columns for later assignment to my parent grid elements class.
CLASS STRING POPULATION
const gridClass = `grid grid-cols-${numCols} gap-2 pt-2`;
//*** At this point, the value of gridClass, if columns were set to 3, using template literals is :
'grid grid-cols-3 gap-2 pt-2'
//The proper string is now populated and passed back in the API response via classCss key
res.status(200).json({ msg: 'Success splitting', tileData: tiles, classCss: gridClass})
PAGE SNIPPET:
<div id="final">
<div className={tileCss} > //<--This is where I pull in the generated class string
{
imageData.map((nft, i)=>(
<div key={i} className='border shadow rounded-x1 overflow-hidden'>
<Image src={nft.imgSrc} alt="image" layout="responsive" width={nft.tileDimX} height={nft.tileDimY}/>
</div>
))
}
</div>
</div>
This sometimes works but other times it doesn't. Usually if I set the columns to 3, it seems to work properly, but if I set it to 5 lets say, regardless of the input image size, it just puts them all in a single column with large images. Oddly however, the parent grid class on the page is correct, it just seems that it isn't adhered to. I will provide some snapshots below to show what I'm talking about. I've been trying to figure this out for a couple days, however I haven't had luck and since I'm new to NextJs I thought I would share here and see if I'm just doing something stupid. Thanks!
The below results also don't seem to care if the viewing window is stretched wide or reduced in size. I just took the snapshots below so that you could see what was happening in a smaller viewing window.
This is the expected result where the image columns should match the columns entered by the user:
Notice how the css class shows up under styles as well:
This is the improper result, where the user selected 5 columns, the image was split into the correct number of columns, but the display of this in the front end grid does not follow the css.
As you can see grid-cols-5 is correct from a class standpoint, but the viewed result doesn't adhere to this.
Grid-cols-5 is in html class but missing under styles applied:
So I finally found the source to the issue. It seems that tailwindcss performs an optimization on classes brought in and if you are not using the class anywhere in your html, it doesn't include those classes. So I not only needed to return my dynamic string with the expected class, but I also needed to add all the classes I would possibly be using into my tailwind.config.js file under the safelist key.
So my config now looks like this and it is working as expected:
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
],
safelist: [
{
pattern: /grid-cols-./,
}
],
theme: {
extend: {},
},
plugins: [],
}
More information can be found here:
https://tailwindcss.com/docs/content-configuration#using-regular-expressions
Thanks again Mohit for your assistance.
One of the problem I noticed is in grid-cols-${numCols} in the line
const gridClass = `grid grid-cols-${numCols} gap-2 pt-2`;
TailwindCSS doesn't allow you to generate classes dynamically. So when you use the following to generate the class… grid-cols-${numCols} as a string.
…TailwindCSS will not pick that up as a valid TailwindCSS class and therefore will not produce the necessary CSS.
You can use the function from where you are getting numCols and instead of returning the value of numCols, simply return grid-cols-${numCols}.
Suppose let say your function be getNumofCols(), then modify it like this
function getNumofCols() {
...
...
...
...
...
return "grid-cols-" + numCols ;
}
So that it returns the complete string .
And use it like again
const gridClass = `grid ${getNumofCols()} gap-2 pt-2`;
If your function uses any parameter then you can create a new function and call this function and just add grid-cols- to the return value.
By doing it this way, the entire string for every class is in your source code, so Tailwind will know to generate the applicable CSS.
I'm using React JS and I've created an autocomplete component that returns a list of results.
Here's my code for the autocomplete :
const [pokedexMatch, setPokedexMatch] = useState([]);
const searchPokedex = (text) => {
if (!text) {
setPokedexMatch([]);
} else {
let matches = pokedex.filter((pokedex) => {
const regex = new RegExp(`${text}`, "gi");
return pokedex?.name?.match(regex);
});
setPokedexMatch(matches);
}
};
Here's a working sandbox with some dummy text below. As you can see, when you type a single letter it returns a lot of results and move the text below the results.
What I'd like to do is limit the number of results to 5 and make the list of results go above the text (I guess that I should use absolute positioning but I'd like to know if there is another method without absolute positioning) ?
To limit your results to 5, use simple Javascript!
setPokedexMatch(matches.slice(0, 5));
For the positioning part of your question, you're on the right track - you can use absolute positioning of a div with a white background to make the results appear to be "above" the text.
EDIT: I've updated your sandbox here and made some very minor changes.
When you map over an array, make sure you include a key prop. Read more here.
I added the slice method to limit your results to 5
I added a simple above class to the parent <ul /> element to make the results appear "above" the text. This is just one way to accomplish this, I'll leave it to you to style it better if you'd like.
I am getting what I am assuming is json data from a wordpress blog endpoint like so:
https://example.com/wp-json/wp/v2/posts
I am looping through and showing the tiles for now:
<div>{posts && posts.map((post) => <h1>{post.title.rendered}</h1>)}</div>
But the post titles are not displaying properly. For example the word Don't shows Don’t
I have discovered that I can use dangerouslySetInnerHTML to fix this issue but is it safe? The fact that it has the word 'dangerously' in it is worrying.
I believe dangerouslySetInnerHTML is the way to go about this - but I will go into more detail as to why "dangerously" is in "dangerouslySetInnerHTML" and hopefully that will help you make an informed decision for your situation.
What dangerouslySetInnerHTML does is render any HTML string given to it within the DOM element.
For example:
<h1 dangerouslySetInnerHTML={{__html: post.title.rendered}} />
(as an aside, note the __html key has two underscores)
Will properly render the string Don’t to Don't.
This is all pretty harmless, however, if, for example, the value of post.title.rendered could be set by an untrusted party (such as an arbitrary user), and if this arbitrary user wanted to do some damage, they could enter a string such as:
<script type="text/javascript>
// Do evil stuff
console.log('I did some evil stuff');
</script>
This code would then be executed by the browser when the page loads - because React would have generated the following DOM:
<h1>
<script type="text/javascript>
// Do evil stuff
console.log('I did some evil stuff');
</script>
</h1>
So with all that in mind, if you are sure that the value of this field is within your control (and not anyone else's) and you also know that there will not be any arbitrary code in these strings, then go ahead and use dangerouslySetInnerHTML.
However, if there is the possibility that someone besides yourself could manipulate this field, I would instead look to something like decode-html-entities - this way you can have the presentation you want, without compromising your app/users.
I've a problem using handlebars that I'm not able to solve, today it's the second day trying to solve it but I'm really stuck.
I'm trying to use handlebars for the first time because I wanted to make the web page I'm working on a bit more dynamic.
On my server I got a mongoDB, there is this search button where the user inputs whatever they want and they have to get user info from any user that match.
The response of that query comes like this:
_id: 5e2201a99162aa0344ed4261,
userName: 'Example',
email: 'example#example.io',
age: '23'
What I'm trying to do is get that data and show it on a div on users dom but for some reason I'm not being able to do it.
On my index.js file on the node server I got this function:
const printSearch = user => {
console.log(user);
res.render("main", {
layout: "index",
users: user
});
};
This function is a callback function of the one that do the query and I know that on this function, user has the result of that query inside because of the console.log(user);.
Then on main.hbs I have the following code:
<div id="result">
{{#if users}}
{{#each users}}
<p>{{users.userName}}</p>
<p>{{users.email}}</p>
<p>{{users.age}}</p>
{{/each}}
{{/if}}
</div>
But for some reason that doesn't work, as I said before, this is my first time using handlebars so I imagine that there is something I'm missing but I'm not being able to figure it out.
It would be really helpful a bit of help in here, I'll be really glad.
Thanks in advance everyone!
To access the current iteration value, don't use {{users.<property>}}, just: {{property}}. If users is an array do:
{{#each users}}
<p>{{userName}}</p>
<p>{{email}}</p>
<p>{{age}}</p>
{{/each}}
Otherwise if users is a single object you can drop {{#each}}
<p>{{users.userName}}</p>
<p>{{users.email}}</p>
<p>{{users.age}}</p>
I would like to be able to achieve something like the following in Quill:
<ul>
<li>Something<br>
Else
</li>
</ul>
Out of the box, Quill removes the br and does not support adding a br inside of an li with either insertText(..., '\n', ...) or user editing.
I see how I can register a keyboard binding to handle, for example, "shift-enter" to be able to author content like this and it seems like both something that is possible to represent in Parchment and that there are the Blots to represent this in Quill (i.e Break, etc).
All that said, it's not clear to me if this use case is possible in the Quill editor through a module or not.
Any pointers would be super appreciated!
Thanks!
Here's a couple constraints to keep in mind:
Quill content must be represented canonically and modified unambiguously through the API. So if you had <ul><li>SomethingElse</li></ul> and used insertText(index, '\n'), there is ambiguity as to produce a <ul><li>Something<br>Else</li></ul> or <p>Something</p><ul><li>Else</li></ul>. In Quill core the former is not possible so there is no such ambiguity (note to produce <ul><li>Something</li><li>Else</li></ul> you would call insertText(index, '\n', 'list', 'bullet');). Therefore if soft breaks are added it cannot be represented with a newline character. The history with \r vs \n vs \r\n suggests it would be a bad idea to produce another newline character as the solution.
Architecturally it was convenient for the Quill data model to always have both a block and a leaf node in the corresponding DOM at all positions. <br> is used as the placeholder so <p><br></p> represents an empty line instead of just <p></p> (also older IE <= 10 did not render any height on <p></p> even if you specified it with CSS so the <br> was historically necessary). Internally blocks will add <br> and automatically when its last child is removed, and remove <br> when children are inserted. Given this special behavior (though modifiable through defaultChild), you do not want to extend the default <br> implementation.
So the suggestion I would make is to create a custom inline embed blot that uses and specify a class so it can disambiguate between the normal <br>. To insert it through the API it would be insertEmbed(index, 'customBr', true); and the JSON representation of <ul><li>Something<br class="custombr">Else</li></ul> from getContents() would be [{ insert: "Something" }, { insert: { custombr: true } }, { insert: "Else" }, { insert: "\n", attributes: { list: 'bullet' } }].
This seems to work but have not tested throughly: https://codepen.io/quill/pen/BJaOxP.