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>
);
Related
<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
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>
I am facing a problem in deleting item from an array. Array splice supposed to work but its not working like I want. Its always delete the item from last. I am using Vue.js . I am pushing item dynamically to an array. But after click remove its delete from the last. why I am facing this. I am attaching the codes.
<template>
<div>
<span class="badge badge-pill mb-10 px-10 py-5 btn-add" :class="btnClass" #click="addBtn"><i class="fa fa-plus mr-5"></i>Button</span>
<div class="block-content block-content-full block-content-sm bg-body-light font-size-sm" v-if="buttons.length > 0">
<div v-for="(item, index) in buttons">
<div class="field-button">
<div class="delete_btn"><i #click="remove(index)" class="fa fa-trash-o"></i></div>
<flow-button v-model="item.title" :showLabel="false" className="btn btn-block min-width-125 mb-10 btn-border" mainWrapperClass="mb-0" wrapperClass="pt-0" placeholder="Button Title"></flow-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import flowButton from '../assets/flow-button'
export default {
name: "textArea",
props:{
index : Number
},
data() {
return {
buttons : [],
btnClass : 'badge-primary',
}
}
components : {
flowButton
},
methods : {
addBtn () {
if(this.buttons.length >= 2) {
this.btnClass = 'btn-secondary'
}
if(this.buttons.length < 3) {
this.buttons.push({
title : ''
});
}
},
remove(index) {
this.buttons.splice(index, 1)
}
}
}
</script>
This must be because of your flow-button I have tried to replicate your error but endup to this code. I just replaced the flow-button with input and it works. Try the code below.
Use v-bind:key="index", When Vue is updating a list of elements rendered with v-for, by default it uses an “in-place patch” strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will patch each element in-place and make sure it reflects what should be rendered at that particular index. This is similar to the behavior of track-by="$index"
You have missing comma between data and components, I remove the component here it won't cause any error now, and more tips don't mixed double quotes with single qoutes.
<template>
<div>
<span class="badge badge-pill mb-10 px-10 py-5 btn-add" :class="btnClass" #click="addBtn"><i class="fa fa-plus mr-5"></i>Button</span>
<div class="block-content block-content-full block-content-sm bg-body-light font-size-sm" v-if="buttons.length > 0">
<div v-for="(item, index) in buttons" v-bind:key="index">
<div class="field-button">
<div class="delete_btn"><i #click="remove(index)" class="fa fa-trash-o">sdfsdff</i></div>
<input type="text" v-model="item.title" :showLabel="false" className="btn btn-block min-width-125 mb-10 btn-border" mainWrapperClass="mb-0" wrapperClass="pt-0" placeholder="Button Title"/>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'textArea',
props: {
index: Number
},
data () {
return {
buttons: [],
btnClass: 'badge-primary'
}
},
methods: {
addBtn () {
if (this.buttons.length >= 2) {
this.btnClass = 'btn-secondary'
}
if (this.buttons.length < 3) {
this.buttons.push({
title: ''
})
}
},
remove (index) {
this.buttons.splice(index, 1)
}
}
}
</script>
I think that you may be facing a conflict with the index prop of your component. Try to use a different name for the index of your v-for loop:
<div v-for="(item, ind) in buttons">
<div class="field-button">
<div class="delete_btn"><i #click="remove(ind)" class="fa fa-trash-o"></i></div>
<flow-button v-model="item.title" :showLabel="false" className="btn btn-block min-width-125 mb-10 btn-border" mainWrapperClass="mb-0" wrapperClass="pt-0" placeholder="Button Title"></flow-button>
</div>
</div>
Try this. Removing an item correctly using this.
<div v-for="(item, ind) in buttons" :key="JSON.stringify(item)">
Image of table
I am trying to fetch data from Random user API and create a table of users. I also want to add feature like sort by last name, pagination to show only 10 items per page and add a option button if user wants to see more than. 10 items on the page I am strugging to build that feature any hellp wilbe appreciated
import React, { Component } from 'react';
import Loader from '../components/Loader/Loader';
import '../util/Fetch.css';
export class Fetch extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
isLoading: true
};
this.sortList.bind(this);
this.compareBy.bind(this);
}
componentDidMount() {
this.fetchData();
}
fetchData() {
const url =
'https://randomuser.me/api/?results=20&nat=us,nz,au&seed=foobar';
fetch(url)
.then(response => {
return response.json();
})
.then(parsedJSON => {
this.setState({
users: parsedJSON.results,
isLoading: false
});
})
.catch(error => console.log('parsing failed', error));
}
compareBy(key) {
return function(a, b) {
if (a[key] < b[key]) return -1;
if (a[key] > b[key]) return 1;
return 0;
};
}
sortList(key) {
let arrayCopy = [...this.state.users];
console.log(
arrayCopy.map(user => {
return user.name.first;
})
);
arrayCopy
.map(user => {
return user.name.last;
})
.sort(this.compareBy(key));
this.setState({ users: arrayCopy });
}
}
render() {
const { users } = this.state;
return (
<div>
{this.state.isLoading ? (
<Loader />
) : (
<div className="table-container">
<div className="pag-header">
<div>
<ul className="pag-box">
<h2>List of Users</h2>
<li>
<hr />
</li>
<li>
Sort By:{' '}
<a onClick={() => this.sortList(this.compareBy, 'last')}>
Last Name
<span>
<i className="fas fa-sort-down" />
</span>
</a>
</li>
</ul>
</div>
<div>
<ul className="pag-box">
<li>
items per page
<label>
<select>
<option value="5">5</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="75">75</option>
<option value="100">100</option>
</select>
</label>
</li>
<li>of</li>
<li>
<a>
<i className="fas fa-angle-left" />
</a>
</li>
<li>
<a>
<i className="fas fa-angle-right" />
</a>
</li>
</ul>
</div>
</div>
<div className="responsive-table">
<li id="table-head" className="table-header">
<div className="col col-1">First name</div>
<div className="col col-2">Last Name</div>
<div className="col col-3">Country</div>
<div className="col col-4">Address</div>
<div className="col col-5">City</div>
<div className="col col-5">State</div>
<div className="col col-7">Zip</div>
<div className="col col-8">Phone</div>
</li>
<ul className="responsive-table">
{users.map(user => (
<li key={user.id.value} className="table-row">
<div className="col col-1" data-label="First Name">
{user.name.first}
</div>
<div className="col col-2" data-label="Last Name">
{user.name.last}
</div>
<div className="col col-3" data-label="Country">
{user.nat}
</div>
<div className="col col-4" data-label="Address">
{user.location.street}
</div>
<div className="col col-5" data-label="Address">
{user.location.city}
</div>
<div className="col col-6" data-label="State">
{user.location.state}
</div>
<div className="col col-7" data-label="Zip">
{user.location.postcode}
</div>
<div className="col col-8" data-label="Phone">
{user.cell}
</div>
</li>
))}
</ul>
</div>
</div>
)}
</div>
);
}
}
EDIT: There were a number of issues with the code in question, and not enough information was given in the question to really understand the scope of the issue. A custom solution was worked out across multiple files in the project to resolve the asker's problem, but it is outside the scope of this question to post that solution here.
In the last few lines, you're trying to sort arrayCopy.map(user => user.name.last) That map will return an array of JUST THE LAST NAME, so like ['jones', 'smith', 'jenkins']. Then you try to sort THAT array by a key, but that array is a plain old array of strings, and the only "key" it has are the indexes (0, 1, 2, etc)
Instead, you should be doing arrayCopy.sort(this.compareBy(key)) and this.sortList('last') to accomplish the sort and save to state.
compareBy = (key) => { // no need to bind arrow functions
return function(a, b) {
if (a[key] < b[key]) return -1;
if (a[key] > b[key]) return 1;
return 0;
};
};
sortList = (key) => {
let arrayCopy = [...this.state.users];
arrayCopy.sort(this.compareBy(key));
this.setState({ users: arrayCopy });
};
EDIT: After looking at your code some more, I see that you are attempting to bind sortList and compareBy, but you're not actually saving those bound methods anywhere. this.sortList.bind(this) returns a bound method, but does not make the original method bound, so whenever you call this.sortList, it still is unbound. Changing it into an arrow function (as above) will make it always bound.
EDIT: Now that you have added the render method, we can see the real problem is in your click-handler:
<a onClick={() => this.sortList(this.compareBy, 'last')}>
Here, you're calling this.sortList with TWO parameters, a function (this.compareBy) and a string ('last'). this.sortList only expects one parameter: the string. This line should read:
<a onClick={() => this.sortList('last')}>
Additionally, because you're implementing this.sortList in that onClick handler as an arrow function, you do not need to bind the sortList method, either in your constructor as in your example (which will not work as implemented) or by converting it to an arrow function (as I suggested in my previous edit). The real problem was A) the click handler passing the wrong parameters, and B) mapping the array to an array of strings before sorting it.
You may use a simple method to sort array;something like
sortList = (key)=>{
let arrayCopy = [...this.state.users];
arrayCopy.sort((a,b) => a.name[key] > b.name[key]);
this.setState({ users: arrayCopy });
}
I have a component that builds a list of images with 2 buttons on each array entry.
One of the 2 buttons has an onClick event which updates its parentComponent so that the image is shown in a bigger view.
Everything works perfectly in the precompilex jsx version. But as soon as i try out the "live" compiled version the onClick event only works once.
To make it work on another element I need to reload the page.
I don't get any console errors. No idea where the error might be.
If you want to recreate it you can paste the code and create a div with the id "bilder".
I am using the latest react version :
<script src="some-react-CDN-0.13.3.js"></script>
<script src="some-react-CDN/JSXTransformer-0.13.3.js"></script>
Heres the source :
var Bilder = React.createClass({
getInitialState: function() {
return {
data:[
['1', '/app/public/imgs/image.jpg', 'bild1.jpg'],
['2', '/app/public/imgs/image.jpg', 'bild2.jpg'],
['3', '/app/public/imgs/image.jpg', 'bild3.jpg'],
['4', '/app/public/imgs/image.jpg', 'bild4.jpg'],
['5', '/app/public/imgs/image.jpg', 'bild5.jpg']
],
currentPic:[],
display:'showBild clearfix dn',
displayBg:'darkBg dn'
};
},
showBild: function(e, data){
this.setState({
currentPic: e,
display: 'showBild clearfix db',
displayBg: 'darkBg db'
});
},
hide: function(){
this.setState({
display: 'showBild clearfix dn',
displayBg: 'darkBg dn'
});
},
render: function() {
return (
<div>
<SingleBild data={this.state.data} chosenBild={this.showBild} />
<BildDetail hide={this.hide} data={this.state.currentPic} display={this.state.display} displayBg={this.state.displayBg} />
</div>
);
}
});
var SingleBild = React.createClass({
getInitialState: function() {
return {
bild:[]
};
},
showBild: function(data, e){
e.preventDefault();
this.props.chosenBild(data);
},
render: function() {
var scopeThis = this;
var displayBild = function(bild){
return <li><img src={bild[1]} alt="" /><span>{bild[2]}</span><a onClick={scopeThis.showBild.bind(null, bild)} href="#"><i className="fa fa-eye"></i></a><i className="fa fa-trash-o"></i></li>
};
return (
<ul className="dashboardUl bilder clearfix">
<h2>Gemeldete Bilder:</h2>
{this.props.data.map(displayBild)}
</ul>
);
}
});
var BildDetail = React.createClass({
hide: function(){
this.props.hide();
},
render: function() {
return (
<div>
<div className={this.props.display}>
<img src={this.props.data[1]} alt="" />
<span>{this.props.data[2]}</span>
<ul>
<li><i className="fa fa-trash-o"></i></li>
<li><i className="fa fa-ban"></i></li>
</ul>
</div>
<div onClick={this.hide} className={this.props.displayBg}></div>
</div>
);
}
});
React.render(<Bilder />, document.getElementById('bilder'));
I think you should remove the mapping of data onto list nodes out of the return statement in render and then bind component Class to to the map callback function.
...
render: function() {
var listNodes = this.props.data.map(function(bild) {
return (
<li>
<img src={bild[1]} alt="" />
<span>{bild[2]}</span>
<a onClick={this.showBild} href="#">
<i className="fa fa-eye"></i>
</a>
<a href="#">
<i className="fa fa-trash-o"></i>
</a>
</li>
)
}.bind(this));
return (
<ul className="dashboardUl bilder clearfix">
<h2>Gemeldete Bilder:</h2>
{listNodes}
</ul>
);
}
Now