How can I use tableRef.onRowSelected to update the UI via the onRowClick property? - material-table

I've written an onRowClick function to change the rows tableData.checked value when the row is click as seen in the answer here #300
I can see the checked state updating in a console log but the checkbox itself does not change visibly until I actually click another rows checkbox. It will then show all the checkboxes that had their tableData.checked values updated. I'd like to be able to have the checkbox actually display this change to the user onRowClick.
Here is my current code:
<MaterialTable
onRowClick={(event, rowData) => {
console.log(event.target, rowData);
console.log(
"Row Selection State Before: " + rowData.tableData.checked
);
rowData.tableData.checked = !rowData.tableData.checked;
console.log(
"Row Section State After: " + rowData.tableData.checked
);
}}
options={{ selection: true}}
/>
This is the state of the UI on my first row click:
Console Log on first row click:
UI After selecting one checkbox (clicking directly on the checkbox of another row):
Console Log after clicking the initial row again:
Is there any way to make sure the UI updates for the MaterialTable component without resetting anything when the checked state is updated programmatically?
I've also gotten tableRef.onRowSelected working properly but the UI still doesn't re-render with the rows checkbox selected.
Here is the codesandbox with the fix I've attempted

Figured this one out with some help from #orestes22 in the official material-table Gitter chat.
Add tableRef to state:
state = {
tableRef: React.createRef(),
}
Then add the tableRef prop to your Material Table
<MaterialTable
tableRef={this.state.tableRef}
/>
Then on the onRowClick prop/function use tableRef to access dataManager and onSelectionChange
<MaterialTable
tableRef={this.state.tableRef}
onRowClick={(event, rowData) => {
// Update the clicked rows checked state
rowData.tableData.checked = !rowData.tableData.checked;
// pass dataManager the current rows checked state and path/ID, the path/ID needs to be an array, ex: [1]
this.state.tableRef.current.dataManager.changeRowSelected(
rowData.tableData.checked,
[rowData.tableData.id]
);
// call the onSelectionChange and pass it the row selected to ensure it updates your selection properly for any custom onSelectionChange functions.
this.state.tableRef.current.onSelectionChange(rowData);
}}
/>

Related

Prevent click:row event on text selection on row

When text is selected in a v-data-table row, the click:row event is fired.
Is there any way to prevent this?
Replicate sandbox
https://codesandbox.io/s/pedantic-nightingale-fbyk2
Instructions
Select any value in the table and watch the console
A workaround would be to check if there was some selected text at the time you clicked. Your rowClick method would be:
rowClick(item) {
if (window.getSelection().toString()) {
return;
}
console.log(item);
}

Vue Google Place Autocomplete-how can I make the selected value display?

I am implementing the component like this:
<place-autocomplete-field
v-model="field"
name="field"
label="Address lookup"
:api-key="api_key.api_key"
placeholder="Start typing here"
#autocomplete-select="onPlaceInput"
>
</place-autocomplete-field>
...
data() {
return {
api_key,
field: null
};
...
While the #autocomplete-select event fires fine, and delivers the selected value, the value displayed in the component's input field does not update on selecting from the place options. All that is in the input field is whatever was typed in there. This is not how it works in the demo on Github. Can anyone spot what I may be doing wrong?

Select Newly Added Row in Office UI Fabric DetailsList

I have a DetailsList for which I need to keep track of the current selection. My problem is I need to update my state when the user changes the selection, but also be able to set the selection when a new row is added. If I'm listening to user events via onSelectionChanged, I can't call setSelectionKey because it will just cycle back and forth.
Possibly related is that since I am adding a new row, I can't select it until the render that repopulates the items, but I'm not sure when I would even call setSelectedKey to ensure that's already done.
I have a version that kind of works by setting a flag to call setItems and then setSelectedKey while temporarily telling onSelectionChanged to ignore it, but I believe it's causing extra renders and doesn't work in all situations.
Thanks for any guidance.
I figured it out. The problem was I was just setting the previously selected item to selected, e.g. selection.setKeySelected(item.id, true). The secret turned out to be setting all of the other items to not be selected. Here are the relevant parts:
const selection = new Selection({
getKey: item => item.id,
onSelectionChanged: () => {
the_chosen_one = selection.getSelection()[0];
// ... do whatever with the item the user just selected ...
}
});
...
// In some handler when you need to select/re-select an item:
const onWhatever = () => {
setChangeEvents(false);
state.items.forEach(item => {
selection.setKeySelected(item.id, item.id === the_chosen_one.id);
});
setChangeEvents(true);
};
...
<DetailsList selection={selection} items={state.items} ...
I'm not sure the setChangeEvents part is necessary, but it didn't hurt. The documentation on this is non-existent so the only way to figure it out is reading the code and browsing through Github issues, but a lot of those turned out to be dead ends. I still don't understand why I have to explicitly de-select items that were never selected in the first place, but that's what it was.
I hope this helps someone else some day.

react-native re - ender component by clicking a button from another component

I have a list of interventions on my "first page". When I click on one, I navigate to its details, "second page", and there, is a button that allows me to start the events. When I click on that button it fills an object from a route : api/current
{
"interventionSummary": {some object}
}
When there's no intervention started :
{
"interventionSummary": null
}
When an intervention is started, it should be ended too so if the users doesn't I want to show a reminder message in the interventions list ("page 1") using: if interventionSummary !== null -> display the message to remind to end the intervention.
The problem is that my object interventionSummary is not updated when I go back on my interventionsList, unless I reload. For another page I was able to use :
this.props.navigation.addListener('focus', doStuff);
But the button and the route used were in the same page. I have tried, forceUpdate, simulate a state change : this.setState({state : this.state}) from solution on google, but nothing is working, I don't know how to make the component interventionsList see the update, or just re render after the click on the "second page"...
I hope that's clear, if anyone knows a way to do that
in your first page create your function.
myMethod() {
//function i want to call in second page
}
in your first page when navigating to second page(in my case when user presses a button) pass a function as a parameter like below:
onPress={() => this.props.navigation.navigate('SecondPage', {
rerenderOutputTitles: () => this.myMethod(),
})}
then in second page call this method wherever you want like below:
this.props.navigation.state.params.rerenderOutputTitles();

Why Is Vue Data Element Changing When I Only Set It Once?

I have created a component that allows users to select objects from a list and put them into another "selected list" lets say. So there are 100 items in the main list and however many in the users selected list. They can of course remove and add items as they want.
There are two buttons at the bottom of the modal. Cancel and Update. Where Cancel forgets anything they have added or removed (essentially an Undo of when they popped up the modal) and Update technically does nothing because when you are adding and removing, I am actually updating the real selected list.
So my data has these two properties (among others of course):
originalSelections: [],
selectedMedications: [],
There is a method that only gets called one time to set the selectedMedications property to whatever the current state of originalSelections is. I have a console.log to prove I am not running this method more than once and it NEVER gets hit again.
console.log('Post Initing');
let Selected = [];
for (let med of this.value.OtherNotFromEpic) {
let match = this.otherMedications.find(x => { return x.value === med });
if (match) {
Selected.push(JSON.parse(JSON.stringify(match)));
this.originalSelections.push(JSON.parse(JSON.stringify(match)));
this.selectedMedications.push(JSON.parse(JSON.stringify(match)));
}
}
I was baffled at why the selectedMedications was changing, so I added a watch to let me know if it was:
watch: {
originalSelections(newValue) {
console.log(' ** Original Selection Changed', this.init, newValue);
},
},
The Cancel method is as follows:
cancel() {
$('#' + this.modalID).modal('hide');
console.log('Cancel: this.originalSelections', JSON.parse(JSON.stringify(this.originalSelections)));
this.selectedMedications = this.originalSelections;
this.$nextTick(() => {
console.log(' Cancelled: this.selectedMedications', JSON.parse(JSON.stringify(this.selectedMedications)));
});
},
You can see that I am setting selectedMedications to whatever it was originally.
The odd thing is... This WORKS 100% the first time I bring up the modal. So I pop up the modal, remove an item, cancel the modal and it brings back the item I removed. Perfect!
If I bring the modal up again, remove that same item or any other item, cancel the modal and that item stays removed and the watch is actually hit. I have NO other place in the code where originalMedications = … or originalMedications.push or even originalMedications.slice ever happen. And it is my understand that the JSON.parse(JSON.stringify(match)) code I use to set it is making a new object and not a reference in any way.
Another odd thing I have found is that if I refresh the page, open the modal, cancel out without doing any adding or removing. Then I bring up the modal again and try either add or remove, then cancel the modal, those items do not revert back to the originalMedications state because originalMedications is the same as selectedMedications. Aargh!
So HOW can a property get altered when I never do anything to it after the initial setting of it?
In the cancel method, when below direct assignment is done here after both data is referring to same (since its array). So any time after the first cancel both originalSelections and selectedMedications array would have same reference and hence same data.
this.selectedMedications = this.originalSelections;
instead better to use concat as below? This will create a copy of originalSelections and assign that to selectedMedications. So any operations on selectedMedications will not affect the originalSelections.
this.selectedMedications = [].concat(this.originalSelections);