A block inside a block in React - javascript

I'm trying to do a text, a line and then a button like the following image:
I have this code and the functionality works fine but the css is wrong:
{ retrospectives.size > 0 &&
<div className='c-division-line u-margin-bottom'>
<h3>
<span> Last Retrospectives </span>
</h3>
</div>
}
{ retrospectives.size > 4 &&
<div className="c-division-line__button u-font-size--12px">
<RetroLink project={projectId} path={path}/>
</div>
}
Now, If I do this (a block of code inside other block) the css is correct but the functionality fails. How can I do this where both the css and functionality works fine?
{ retrospectives.size > 0 &&
<div className='c-division-line u-margin-bottom'>
<h3>
<span> Last Retrospectives </span>
</h3>
{ retrospectives.size > 4 &&
<div className="c-division-line__button u-font-size--12px">
<RetroLink project={projectId} path={path}/>
</div>
}
</div>
}
I thought about doing the following function but it didn't work:
buttonLink () {
const { retrospectives, projectId, path } = this.props
if (retrospectives.size > 4) {
return <div className="c-division-line__button u-font-size--12px">
<RetroLink project={projectId} path={path}/>
</div>
}
}
And calling it like this
{this.buttonLink()}

I'd recommend making your button element into a variable, like this:
const allRetrospectivesButton = retrospectives.size > 4 && (
<div className="c-division-line__button u-font-size--12px">
<RetroLink project={projectId} path={path}/>
</div>
);
return retrospectives.size > 0 && (
<div className='c-division-line u-margin-bottom'>
<h3>
<span> Last Retrospectives </span>
</h3>
{ allRetrospectivesButton }
</div>
);

Related

DOM not getting updated Vue

<li
v-for="(schema) in typeSchema"
:key="schema.id"
>
<div style="display:inline-block; width:100%;">
<div style="display:flex; justify-content:space-between">
<span>{{ schema.title }}</span>
<span v-if="schema.controller">
<MdsSwitch
:checked="schema.controller.value"
:label="schema.controller.title"
#change="toggleController(schema, $event)"
/>
</span>
</div>
<div style="display:flex;flex-flow:column;place-items:flex-start;align-items:flex-start;margin-top:10px;">
<component
:is="schema.type"
v-bind="schema"
:data="data"
:is-disabled="schema.isDisabled"
#input="updateData"
/>
</div>
</div>
</li>
# toggleController(schema, event) {
if (schema.controller) {
// this.typeSchema.map(x => x).in
schema.controller.value = event;
schema.isDisabled = !event;
schema = { ...schema };
// const index = this.typeSchema.findIndex((x) => x.id === schema.id);
// console.log(index);
// this.$set(schema, "isDisabled", !event);
// this.typeSchema.splice(index, 0, schema);
}
},
When toggleController is executed it should disable the associated component, it was working earlier and I'm not sure what change I made and it stopped working, unfortunately everything is on my local so cannot refer pervious versions.
I have tried $set, splice but no luck

Vue js: load more data button not working properly

In my Vue.js code below I'm trying to add a Show More button to my data coming from API so initially it should show 10 data and whenever clicked load more 10 and so on. I tried answer from:
Load more button in vuejs
but it's not working since I'm looping over an array it gives me the error below can't read property of question title. Is there a way to do it?
<div class="search-askbutton">
<b-row>
<div class="search-wrapper">
<input
type="text"
v-model="search"
placeholder="Search something..."
class="fas fa-search"
/>
</div>
<div class="container vue">
<div v-for="commentIndex in commentsToShow">
<div v-if="commentIndex <= commentsToShow">
<ul
class="container-question"
v-for="(question, index) in filteredList"
:key="index"
>
<div>{{question[commentIndex - 1].questionTitle}} says:</div>
<hr />
</ul>
</div>
</div>
<button #click="commentsToShow += 10">show more</button>
</div>
<script>
export default {
data() {
return { commentsToShow: 10,
search: '',
questions: [],}
},
computed: {
filteredList() {
return this.questions.filter((question) => {
return (
question.questionTitle
.toLowerCase()
.includes(this.search.toLowerCase()) ||
question.owner.username
.toLowerCase()
.includes(this.search.toLowerCase()) ||
question.questionTitle
.toUpperCase()
.includes(this.search.toUpperCase()) ||
question.owner.username
.toUpperCase()
.includes(this.search.toUpperCase())
);
});
},
},
mounted: function() {
questionService.getAllQuestions().then((response) => {
this.questions = response.data.response;}
}
</script>
The problem is your subtraction
<div>{{question[commentIndex - 1].questionTitle}} says:</div>
If commentIndex = 0 then you'll be saying 0-1 = -1 therefore it will not find the -1 index.
You could replace this line
<div v-if="commentIndex <= commentsToShow">
So that it can run only if the index is greater than 0
<div v-if="commentIndex > 0">
1)
v-for returns what's inside an array, not the array itself.
<div>{{question.questionTitle}} says:</div>
2)
also, you can remove the v-for loop.
note:- your reference question is also uses this way.
<div v-for="commentIndex in commentsToShow">
<div v-if="commentIndex <= commentsToShow">
<ul class="container-question">
<div>{{filteredList[commentIndex - 1].questionTitle}} says:</div>
<hr />
</ul>
</div>
</div>

Angular 6 timer issue

I have a view which polls an endpoint every 30 seconds and updates if there are changes. In the same view I have a div which is shown/hidden every 7 seconds. The timers are started at the same time.
The first few times it runs, it runs perfectly. It's not until the first 30s timer polls again that it basically starts flickering back and forward every 2 seconds - which it shouldn't.
component.ts
getScreen(tapCode) {
timer(0, 30000)
.pipe(mergeMap(() => this.dataService.get_screen(tapCode)))
.subscribe(objectResp => {
this.callResp = objectResp.status;
this.polledObj = objectResp.items;
this.landing = false;
this.loaded = true;
this.unavailable = objectResp.items.unavailable;
localStorage.setItem('ontapCode', tapCode);
this.getAds(this.polledObj);
});
}
getAds(polledObj) {
this.showAd = false;
this.adTimer = timer(0, 7000);
this.adSubscription = this.adTimer.subscribe(() => {
if(this.timerCount >= this.polledObj.adverts.length) {
this.timerCount = 0;
}
if(this.timerCount <= this.polledObj.adverts.length) {
this.adImage = this.polledObj.adverts[this.timerCount].filename;
this.timerCount++;
}
this.showAd = !this.showAd;
});
}
component.html
<div *ngIf="callResp === 'OK'" class="tap">
<div *ngIf="unavailable === '1' || unavailable === 1" class="object-unavailable">
<img src="./assets/unavailable.png" class="unavailable-img">
</div>
<div *ngIf="unavailable === '0' || unavailable === 0">
<img src={{polledObj.img}} class="img-object">
<div class="container">
<div *ngIf="showAd === true">
<div class="advertisement">
<img src={{adImage}}" class="img-ad">
</div>
</div>
<div *ngIf="showAd === false">
<div class="object-detail-container">
<h3 (click)="resetStorage()" class="object-name text-white">{{polledObj.object_name}}</h3>
<h4 class="text-white object-brewery">{{polledObj.brewery}}</h4>
<h4 class="text-white object-style">{{polledObj.style}} - {{polledObj.abv}}%</h4>
<div class="object-sizes" *ngFor="let size of polledObj.sizes">
<span class="object-size-name">{{size.name}}: </span>
<span class="object-size-volume"> {{size.volume*1000}}ml </span>
<span class="object-size-price"> ${{getPrice(size.price)}} </span>
<span class="object-size-std"> {{getSizeStd(size)}} </span>
<span class="object-size-std-drinks"> std drinks</span>
</div>
</div>
</div>
</div>
</div>

How to render array entries in JSX using map() function with conditional wrapping

I have an array of objects in JavaScript and I want to loop through these objects and return some JSX with bootstrap classes in it such that each row always gets 2 columns displayed inside it.
options: [
{
"letter":"A",
"text": "14 March 1879"
},
{
"letter":"B",
"text": "14 March 1897"
},
{
"letter":"C",
"text": "24 May 1879"
},
{
"letter":"D",
"text": "24 June 1879"
}
]
In my experience with other languages and template engines, it is pretty simple: You just create an opening and a closing div tag with a class of row and then using your template engine, you loop through and render each object until when the counter of your loop is 2, you dynamically end that role and start a new one.
Something like this:
<div class="row">
for (var i in options) {
if(i%2 === 0) {
<!-- render object ... -->
</div><!-- then end this row -->
<div class="row"><!-- start new row -->
} else {
<!-- render object -->
}
}
</div>
I tried this method inside my map function and it was giving a syntax error because the value returned in the case where the condition passes is not valid JSX.
Thanks for any help.
Edit:
In the End, what I want to achieve is this:
If the array of objects contains 2 objects, I should be able to dynamically display it like this:
<div class="row">
<div class="col-md-6">
<div class="option correct-option">
A <!-- that is, option.letter -->
</div>
</div>
<div class="col-md-6">
<div class="option wrong-option">
B <!-- that is, option.letter -->
</div>
</div>
</div>
if the array contains 3 objects, I want to achieve this:
<div class="row">
<div class="col-md-6">
<div class="option correct-option">
A <!-- that is, option.letter -->
</div>
</div>
<div class="col-md-6">
<div class="option wrong-option">
B <!-- that is, option.letter -->
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="option correct-option">
C <!-- that is, option.letter -->
</div>
</div>
</div>
How about something like this?
{options.map((option, i) => (
i % 2 === 0 ? null : ( // skip every 2nd row
<div class="row">
A: {option}
B: {i < options.length ? options[i + 1] : null}
</div>
)
)}
You could use a regular for loop increasing i with 2 every loop, and check if the second option is set to take care of an array of uneven length:
Example
function App() {
const content = [];
for (let i = 0; i < options.length; i += 2) {
content.push(
<div class="row">
<div class="col-md-6">
<div class="option correct-option">{options[i].text}</div>
</div>
{options[i + 1] && (
<div class="col-md-6">
<div class="option correct-option">{options[i + 1].text}</div>
</div>
)}
</div>
);
}
return <div>{content}</div>;
}
HTML:
Result:
Validations:
Works with:
Array.length = 0
&
Array.length = n
You want 3 Cols?... define a const instead magic number "2"....
Code:
const options = [
{
"letter":"A",
"text": "14 March 1879"
},
{
"letter":"B",
"text": "14 March 1897"
},
{
"letter":"C",
"text": "24 May 1879"
},
];
return (
<>
{
Array.from(Array(Math.round(options.length / 2)).keys()).map((number, index) => {
return (
<div className="row">
{
options.slice(index * 2, (index * 2) + 2).map(option=>{
return (
<div className="col-md-6">
<div className={`option ${option.true ? 'correct-option' : 'wrong-option'}`}>
{option.letter}-{option.text}
</div>
</div>
);
})
}
</div>
);
})
}
</>
);

Trying to map array in React, getting not defined

Below is a section of my render and then the component that it references. I am getting "li not defined". I have tried wrapping it in {} and at this point not sure what I am missing. Thanks for the help.
Render section:
var uls = _.chunk(_.take(this.state.results, maxICanShow), perColumn);
return (
<div>
uls.map((lis) => {
<ul className="appt_bd">
<li className="appt_bd_header" style={{ width: colWidth + '%' }}>
<span className="appt_bd_header_main">{this.props.title}</span>
<span className="appt_bd_header_sub">Appts Set</span>
<span className="appt_bd_header_sub">Appts Show</span>
</li>
lis.map((li) => <AppointmentBoardRow key={li.userId} row={li} />)
</ul>
})
</div>
);
Here is the component it references:
var AppointmentBoardRow = React.createClass({
render: function () {
var row = this.props.row;
return (
<li className="appt_bd_row" style={{ width: this.props.colWidth + '%' }} key={row.userId}>
<span className="appt_bd_desc">
<span className="appt_bd_rank">{row.rank}</span>
<span className="appt_bd_avatar_container"><div className={row.className}><span className="initials">{row.initials}</span></div></span>
<span className="appt_bd_user">
<span className="appt_bd_description_main">{row.userName}</span>
<span className="appt_bd_description_sub">{row.role}</span>
</span>
</span>
<span className="appt_bd_data">
<span className="appt_bd_data_main">{row.apptsSetCount}</span>
<span className="appt_bd_data_sub">/{row.apptsSetGoal}</span>
</span>
<span className="appt_bd_data">
<span className="appt_bd_data_main">{row.apptsShowCount}</span>
<span className="appt_bd_data_sub">/{row.apptsShowGoal}</span>
</span>
</li>
);
}
});
It looks like there are a couple of small syntax errors in your first code snippet. Specifically, the call to uls.map is javascript within html syntax, so should be wrapped in {}. The same applies to lis.map.
Additionally, uls.map((lis) => { <ul>...</ul> } is a function that does not return anything. You might instead want to represent it as uls.map((lis) => ( <ul>...</ul> ), or uls.map((lis) => { return (<ul>...</ul>) }. You might want to use the latter and set a debugger to figure out what exactly is happening to the passed in data if the problem still persists.
I took a pass at fixing the syntax errors I mentioned above, hope this helps.
var uls = _.chunk(_.take(this.state.results, maxICanShow), perColumn);
return (
<div>
{
uls.map((lis) => (
<ul className="appt_bd">
<li className="appt_bd_header" style={{ width: colWidth + '%' }}>
<span className="appt_bd_header_main">{this.props.title}</span>
<span className="appt_bd_header_sub">Appts Set</span>
<span className="appt_bd_header_sub">Appts Show</span>
</li>
{ lis.map((li) => <AppointmentBoardRow key={li.userId} row={li} />) }
</ul>
)
}
</div>
);

Categories

Resources