how to save an object using a button in reactjs - javascript

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>

Related

How to pass value to modal using React.js?

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.

React - Table rows only render after unrelated function call

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 });
});
}

Vue JS this.$set not updating reactivity

I have a v-for rendered table that has products in it. This table has a column for "active" status where i want the user to be able to click the active button and it becomes inactive or click the inactive button and it becomes active (a toggle switch basically).
I have this implemented by making a POST call to an api route where my status is updated. This works fine.
The problem is that I cannot get vueJS to update the affected object in the array more than once. this.$set works ONE time. If I hit the toggle switch a second time, it no longer works.
This is my table:
<table class="table table-striped fancy-table">
<thead>
<tr>
<th class="text-center"> </th>
<th>Product/Service</th>
<th class="text-center">Status</th>
<th class="text-center">Date Added</th>
<th class="text-center">QTY Sold</th>
<th class="text-center"> </th>
</tr>
</thead>
<tbody>
<tr v-for="(service, index) in services">
<td class="text-center">
<img v-if="service.featured_image" :src="service.featured_image" class="table-thumb">
<img v-else src="/img/default-product.png" class="table-thumb">
</td>
<td>{{service.service_name}}<span class="secondary">${{parseFloat(service.price).toFixed(2)}}</span></td>
<td class="text-center">
<i class="fas fa-circle active"></i>
<i class="fas fa-circle inactive"></i>
</td>
<td class="text-center">{{ service.created_at | moment("dddd, MMMM Do YYYY") }}</td>
<td class="text-center">10</td>
<td class="text-center"><i class="fal fa-edit table-action-btn"></i></td>
</tr>
</tbody>
</table>
This is my method controlling the update:
updateStatus: function(service, index, status) {
// Grab the authorized user
const authUser = JSON.parse(window.localStorage.getItem('authUser'))
// Add a role and refresh the list
this.$http.post('/api/vendor/services/update/' + service.id + '?updateActive=' + status, { }, { headers: { Authorization: 'Bearer ' + authUser.access_token } }).then((response) => {
// update this service
this.$set(this.services, index, response.body);
}).catch(function(error){
console.log(error);
})
}
EDITS:
I've added a :key param to the v-for table, but I'm still getting the same issue. As you can see in my network panel, the first time you click the button, it goes as expected. Posts to the api route with updateActive=0. The second time you click the button it posts to the api route with updateActive=1 and the data is changed server side, but at this point, my object in the services array is not updated, so it now just continually posts with updateActive=1 rather than showing my other button (toggle switch like i'm wanting).
Here's a screenshot of my network panel with 4 clicks on the button.
The problem here might be with a missing key in your v-for
<tr v-for="(service, index) in services">
you could use the key from the index, but in some occasions that may also cause an issue (for example, when removing a single item in an array, the last DOM object will be removed, because the keys shift over)
<tr v-for="(service, index) in services" :key="index">
Ideally you could use something unique from the data like
<tr v-for="(service, index) in services" :key="service.id">
Thanks to #Daniel above, the answer was that I was expecting a number value back (as it is set to an integer in MySQL) and my ajax call was returning that field as a string.

Ability to toggle True/False with ( v-if ) in the loop

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>

Angular 2 - Pagination next is not triggering the function to load the data for the next page

I am new to Angular 4 and I am stuck in writing the code for pagination.
I am using separate services named "paginationFirst()" and "paginationNext()" to load the data for the first page and next page respectively in a table. So that on clicking the "First" tab , the data from the first service should be loaded in the table through "firstPage()" function and on clicking the "Next" tab, the data from the second service should be loaded in the table through "nextPage()" function.
The data for the first page is loading fine but it is not loading the data for the next page when the next tab is clicked.
Both the services are working fine and displaying the correct data. I do not want to use npm pagination.
Please help in this regard.
HTML:
<div>
<table class="table table-hover">
<thead>
<tr>
<th class="align-right">VALUE</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of calendarTableSelected">
item.value
</tr>
</tbody>
</table>
</div>
<div class="pagination" *ngIf="tableDiv">
<div>
<a href="#" class="active" (click)="firstPage()" >First</a>
</div>
<div>
Prev
</div>
<div>
Next
</div>
<div>
Last
</div>
</div>
component.ts
firstPage(){
this.calendarService.paginationFirst().subscribe(data =>
this.calendarTableSelected = data);
}
nextPage(){
this.calendarService.paginationNext().subscribe(data =>
this.calendarTableSelected = data);
}
Service.ts
public paginationNext(){
return this.http.get(environment.serverUrl+ '/api/nextpage')
.map((responsePage:Response) => responsePage.json())
.catch((err) => {
console.log('Error while getting response from service: '+ err);
return Observable.throw(err)
})
}
public paginationFirst() {
return this.http.get(environment.serverUrl+'/api/firstpage')
.map((resService4:Response) => resService4.json())
.catch((err) => {
console.log('Error while getting response from service: '+ err);
return Observable.throw(err)
})
}
Please click here to see the screen from the developer tools displaying that the service is returning response
Screenshot for the network tab
I have found the solution. Below I am posting my answer.
<div>
<button class="active" (click)="firstPage()" >First</button>
</div>
<div>
<button (click)="previousPage()">Prev</button>
</div>
<div>
<button (click)="nextPage()">Next</button>
</div>
<div>
<button (click)="lastPage()">Last</button>
</div>
In your component, you set the value like this :
this.calendarTableSelected = data
But in your HTML, you iterate like this
*ngFor="let item of calendarTable"
Either you weren't aware of that, or you forgot some piece of code !

Categories

Resources