I have a table that returns data after a .data.map().. as shown below:
{this.state.data.map((item, i) => {
return (div>
<tr>
<td>{item.id}</td>
<td>{item.name}</td>
<td>{item.symbol}</td>
And a <td> in the same <table> and <tr> above that displays my modal with the below code:
<td>
<div>
<a className="btn" href="#open-modal" title="More Details">👁</a>
<div id="open-modal" className="modal-window">
<div>
❌
<div>Update Details</div>
<label>{item.id}</label> //WHERE I WANT TO DISPLAY MY ID
</div><a href={url}></a></div>
</div>
</td>
Now when I want to display the item.id of each particular row after opening the modal, it returns the item.id of only 1 item in the array and not the actual item.id.
So the item.id in <td> is different from the item.id in the modal. It keeps returning the same item.id for every row I click on. How can I have these 2 have the same value?
The modal only reference to your last id at the time you rendered it
I would suggest you have a state to store your id and render it when you open your modal.
Something like:
const [selectedId, setSelectedId] = useState();
<td>
<div>
<a
className="btn"
onClick={() => setSelectedId(item.id)}
href="#open-modal" title="More Details"
>👁</a>
<div id="open-modal" className="modal-window">
<div>
❌
<div>Update Details</div>
<label>{selectedId}</label>
</div><a href={url}></a></div>
</div>
</td>
The 👁 looks scary though.
Related
Currently, I have a WebSocket chat messager using react js, I want to have it save the message object when I click on its associated button so that it will pin it. How do I get a button press to save the object it's associated with?
Currently, I have an array of objects that just stack on top of each other like so:
{messages.map(message => (
<>
<tr>
<td>{message.message}</td>
<td><button id="pin_button" type="button" >Pin Message</button></td>
</tr>
</>
))}
What I want to do is have it when I press that button it will save that object and preferably send it to a WebSocket so that other people can see the message that was pinned
You should use state.
const [savedMsgs, setSavedMsgs] = useState([]);
<ul className="saved-msgs">
{savedMsgs.map((msg,i) => <li key={i}>{msg.message}</li>)}
</ul>
<tr>
<td>{message.message}</td>
<td>
<button
id="pin_button"
onClick={() => setSavedMsgs([...new Set([...savedMsgs, message])])}
>
Pin Message
</button>
</td>
</tr>
I have a weird bug that I've been trying to debug for a few hours now but just can't seem to figure it out. Essentially my table rows won't render unless a function that calls setState is run.
My table is formatted like so:
<table classname="ui inverted table">
<thead>
<tr>
<th>Lobby name</th>
<th>Players</th>
<th>Mode</th>
<th>Difficulty</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{this.renderRow()} //Table rows
</tbody>
</table>
The rows are rendered by this function, that maps over an array of objects:
renderRow = () => {
return games.map(function(val, i){
return(
<tr key={i}>
<td>
{val.name}
</td>
<td>
{val.currentPlayers}/4
</td>
<td>
{val.gameMode}
</td>
<td>
{val.difficulty}
</td>
</tr>
)
})
}
Now here is the weird bug. The rows won't render unless I tap a button which calls createGame. The only thing createGame does is: this.setState({show: true})
The Menu is:
<div classname="ui inverted segment">
<div classname="ui large inverted pointing secondary menu">
<button classname="active item">
Lobby
</button>
<div classname="ui right inverted pointing secondary menu">
<button classname="item menu_item" onclick={this.createGame}>
//Have to click this button to render rows for some reason.
<i classname="plus circle icon"></i>
Create Game
</button>
<div classname="item">
<img classname="ui mini circular image" src={this.state.photoURL}></img>
<span classname="menu_name">{this.state.userName}</span>
</div>
</div>
</div>
</div>
CreateGame for reference as well:
createGame = () => {
this.setState({show: true})
};
It seems like it's really the show attribute in state that's triggering the table rows for some reason, but it's not being conditionally rendered so I don't understand why triggering that state param would cause the rendering. If I manually set show: true in React devtools the table rows render as well.
EDIT: games is being populated like so:
componentDidMount(){
//DB listner, gets all games on component mount, and all new games.
db.collection("games")
.onSnapshot(function(querySnapshot){
querySnapshot.forEach(function(doc){
games.push(doc.data())
});
console.log(games);
});
}
As componentDidMount is only called after the first rendering, your table rows will not be rendered initially. The games array is empty at this point.
It would make sense to move games into the component state here. Thereby automatically updating the state, once the games have been loaded. Remember, a setState will usually trigger a re-render.
componentDidMount(){
//DB listner, gets all games on component mount, and all new games.
db.collection("games").onSnapshot(function(querySnapshot) {
const loadedGames = querySnapshot.map(function(doc) {
return doc.data();
});
// update the state
this.setState({ games: loadedGames });
});
}
A table is rendered with rows based on the values inside the array 'results'. There is a dropdown present in each of the row, which is populated via an array 'statuses'.
<div id="app">
<table>
<tr v-for="(row,index) of results">
<td>{{index}}</td>
<td>{{row.name}}</td>
<td>
<div :id="row.id"
class="ui selection dropdown status_dropdown">
<i class="dropdown icon"></i>
<div class="text">{{row.status}}</div>
<div class="menu">
<div class="item" v-for="status of statuses"
:data-index="index">
{{status.status}}
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
Following is change dropdown function, which basically removes the row if the selected text in dropdown is "Delete":
$('.status_dropdown').dropdown({
onChange: function(value, text, $choice) {
let temp_index = $($choice).attr("data-index");
if(text === "Delete"){
vm.results.splice(temp_index,1);
}
}
});
Here's a codepen with complete code: https://codepen.io/anon/pen/KxzZOB
Now, if the status is changed to "Delete", although the row gets removed, the value of dropdown "Delete" is getting retained on that row.
To reproduce in the codepen sample, change the first row's status (index 0) to "Delete". You'll see that status for "Doe" appears as "Delete".
Also, if any of the dropdown value is changed. And some other row's dropdown value is changed, the previous row for which the status was changed retains the value.
To reproduce in the codepen sample, reload the page. Now, change the status for third row (index 2) to "Active". Now delete the second row (index 1) by selecting "Delete". You'll see last row retaining the value "Active".
Can someone help me out with this issue?
To resolve this issue, you can define the key. see below:
<div id="app">
<table>
<tr v-for="(row,index) of results">
<td>{{index}}</td>
<td>{{row.name}}</td>
<td>
<div :id="row.id"
:key="row.id"
class="ui selection dropdown status_dropdown">
<i class="dropdown icon"></i>
<div class="text">{{row.status}}</div>
<div class="menu">
<div class="item" v-for="status of statuses"
:data-index="index">
{{status.status}}
</div>
</div>
</div>
</td>
</tr>
</table>
</div>
Defining the key should maintain the dom item instance while it moves within the table.
I am asking about hiding and showing an element in Vue.js
I always use this
<ele v-if="value" />
and then set {value} in Vue Instance data object, then toggle True/False for toggle visible, but now in my situation , my v-if condition put in some element , then this element create with v-for directive
some thing like this
<div v-for="item in items" >
<ele v-if="value" :key="item.i" />
<ele v-if="value" :key="item.i" />
<ele v-if="value" :key="item.i" />
// this button fire a method for Change (toggle) value (used for v-if)
<button #click="ToggleValue" > update </button>
</div>
In my view i have a table contain some rows and each rows have some field ( all field have v-if directive ) and in each rows we have button for fire method
Now what is my question ?!!
At the end my table is doing this , when click on every button ToggleValue method execute and toggle value of (value) object , now all field in all rows change the value ( all thing doing right :D )
but I want click on every button in each row just change the value of that row
I have dummy way
< ele v-if="value(item.id)" />
.........
.........
<button #click="ToggleValue(itme.id)" >
if my index of loop is Const and static I use this way , but now items in loop are dynamic
all thing was in my pen at here , thanks for give me your time
https://codepen.io/hamidrezanikoonia/pen/OQGrPB?editors=1100
Instead of having a single value, turn value into an object (or array) and index it by item.id.
Updated codepen: https://codepen.io/acdcjunior/pen/MQRZmK?editors=1010
In your pen, the JavaScript:
...
],
update_:false
},
methods: {
set_update() {
this.update_ = !this.update_;
}
}
becomes:
...
]
update_: {1: false, 2: false, 3: false}
},
methods: {
set_update(id) {
this.update_[id] = !this.update_[id];
}
}
And the template:
<td :key="getValue.id+4" v-if="update_" mode="in-out" > {{ getValue.rate_curr }} </td>
...
<button #click="set_update()" type="button" class="btn btn-primary"> Update </button>
becomes:
<td :key="getValue.id+4" v-if="update_[getValue.id]" mode="in-out" > {{ getValue.rate_curr }} </td>
...
<button #click="set_update(getValue.id)" type="button" class="btn btn-primary"> Update </button>
I have a string Data in my model that can be pretty long. I'm trying to take the first 150 chars and then make it clickable, and when the link is clicked a new div should appear with the whole message. Below am I using tag, but I dont know how to give it a unique ID and make it store my item.Data.
Can someone help me with some ideas?
#foreach (var item in Model) {
<div class="row">
<div class="col-md-1">
#Html.DisplayFor(modelItem => item.Level)
</div>
<div class="col-md-2">
#Html.DisplayFor(modelItem => item.Source)
</div>
<div class="col-md-1">
#Html.DisplayFor(modelItem => item.Date)
</div>
<div class="col-md-5">
<a ID="?">#Html.DisplayFor(modelItem => item.Data).ToString().Substring(0, 150) ...</a>
</div>
<div class="col-md-1">
#Html.DisplayFor(modelItem => item.Count)
</div>
</div>
}
Essentially, you'll just need something like this:
<a class="show-data" href="#AllData">
#item.Data.Substring(0, 150)
</a>
<div id="#AllData" style="display:none">
#item.Data
</div>
Then, a bit of JS:
$('.show-data').on('click', function () {
$($(this).attr('href')).toggle();
});
Take note, though, for simplicity of the example, I just assigned the div an id of AllData. Since this is inside a foreach loop, you'll need to use something to make each id unique. This could be the id of the item or you could use a for loop instead of foreach, and then use the index. Just be sure to make the href of the link and the id of the div match and be unique for the page.
#Html.DisplayFor(modelItem => item.Data).ToString().Substring(0, 150)