React useState isn't setting opposite boolean correctly - javascript

I have a simple button on page with onClick event, and then useState hook that is by default set to false. Then I have elements on page, when I click on them I wanna do an action, but only if the state of that useState hook is set to true, which is done by if condition, but for some reason it passes it, even though the state should be false. My code:
Initiating the hook:
const [ isEraser, setIsEraser ] = useState(false);
Setting state on button click:
<span
className="scroll"
onClick={() => {
setIsEraser((isEraser) => !isEraser);
}}
>
The condition:
console.log('Eraser is set to', isEraser);
if (isEraser == true) {
// Code
}
The output of the console.log:
no changing state (is default false) -> false
changing state to true -> true
changing state back to false and triggering that event in which the condition is -> false, true, false
Edit:
I can't pass full component code, because it's kinda big, and some parts of code are protect by client contract, but the condition is in onClick event:
$body.on('click', '.tvs-annotated-text, .tvs-annotate-element', function(
e
) {
console.log('Eraser is set to', isEraser);
if (isEraser === true) {
setIsAlert(1);
// Odstraníme vybranému elementu backround
this.style.backgroundColor = '';
this.classList.remove('tvs-annotated-text');
this.classList.remove('tvs-annotate-element');
}
});

pretty sure you just need to do setIsEraser(!isEraser)

You don't have to use a function to set state setIsEraser((isEraser) => !isEraser); → setIsEraser(!isEraser)

Allright, so the problem was that the onClick trigger was written in jQuery, after rewriting it to normal javascript it works now. Big thanks to you guys.

In the setIsEraser you need to pass the last state. you passed the initial state in it so every time you press the button it passes false as isEraser.
change the isEraser in setIsEraser function to something else like pre or previous, etc.
<span
className="scroll"
onClick={() => {
setIsEraser((pre) => !pre);
}}
>
In this way pre would be the last state not the initial state and your program will work just fine.

Related

Prevent MatDialog From Closing When Clicked Outside with pending changes

I want to prevent close on outside when there are pending changes.
I something like this, but with no result.
this.dialogRef.beforeClosed().subscribe(() => {
this.dialogRef.close(false);
//some code logic
//...
});
The disableClose on MatDialog have to stay false
Initially, while opening dialog, you can pass 'disableClose' as true, and later manually close dialog on backdrop click or escape click if there are no pending changes.
this.dialog.open(DialogComponent, { disableClose: true });
dialogRef.backdropClick().subscribe( () => {
if(!pendingChanges) dialogRef.close();
// else do nothing
});
Depending on the case, you can initially set disableClose as false, so that user can close it if there is no pending changes, depending on what that pending change is, if it is an async call for example, you can set the disableClose as true.
You can also then inject the MatDialogRef into the component itself and manually toggle disableClose per your requirements, so something like this:
constructor(private matDialogRef: MatDialogRef<WhateverYourDialogIsCalled>) {}
then in a async call it could be:
onSubmit() {
this.matDialogRef.disableClose = true;
this.myService.doSomething().subscribe(_ => {
this.matDialogRef.disableClose = false;
});
}

How do I NOT trigger the onChange callback in Angular 11 a Reactive Form

In my project I save information by every change in an input field with the registerOnChange method. But in a particular usecase I don't want to call the callback from the registerOnChange. I
Here is a summary of my code
textInputControl: FormControl = new FormControl();
...
this.textInputControl.registerOnChange(() => {
this.textInputChangeHandler();
});
...
this.textInputControl.setValue("trigger the registerOnChange");
this.textInputControl.setValue("NOT trigger the registerOnChange").doNotTriggerOnChange(); // Hope the solution will something like this
Try { emitEvent: false } as the second argument.
this.textInputControl.setValue("NOT trigger the registerOnChange", { emitEvent: false });

Vue JS Event bus data not working outside scope of event

I am using event bus to show alert on update data.so whenever user update the data i want to show an alert showing "Data is udpated" so for that i am using event bus
here is BlogEdit.vue Component where i am firing event
app.$router.push('/', () => {
vueBus.$emit('showAlertBox')
})
And In BlogList.vue I am listning for this event
data: function(){
return {
showalert: false,
}
},
vueBus.$on('showAlertBox',(data) => {
this.showalert = true;
console.log(this.showalert); //Returns True
})
console.log(this.showalert); //Returns False
But the result is unexpected as it change back to false.
Why this.showalert changed to false ? So that cause to not showing alert box.
Since i am new to vue js i read the documenatation and other solutions but i cant figure out where am i going wrong with this.

React componentDidMount not called on component reload

I have a list of data table. In data table I have data w.r.t to some device Whenever I click ID I open a sidebar with some data displaying inside that.
The problem what I am facing is onclick of ID first time it calls the api gets the data and displays properly. But, after closing sidebar when I click again on ID it doesn't load anything (no calls for APIs).
I am not able to create code pen for that but below is my code.
My Code -
onCLick ID -
_onClickCompliance(deviceId);
const _onClickCompliance = deviceId => {
ReactDOM.render(
<ComplianceDetails deviceId={deviceId} />,
document.getElementById("ComplianceDetailsModalDiv")
);
};
Inside ComplianceDetails component - First time onClick it goes inside componentDidMount but on click again it's not. That's why I have componentDidUpdate for this. If I remove this componentDidUpdate, it always loads the old data in sidebar after onCLick of ID in table.
`getDetailsByDeviceID` this is called to get the data from API and sets value in state
My Code -
componentWillReceiveProps() {
this.setState({ sideBarShow: true });
}
componentDidMount = () => {
this.getDetailsByDeviceID();
};
componentDidUpdate(prevProps) {
if (this.props.deviceId !== prevProps.deviceId) {
this.getDetailsByDeviceID();
}
}
getDetailsByDeviceID code -
getDetailsByDeviceID = () => {
try {
this._getComplianceDetailsApi(); //apis
} catch (err) {
toast({
message: err,
flavor: "error",
options: { isHtml: true }
});
}
};
If I remove this it calls the page indefinitely.
if (this.props.deviceId !== prevProps.deviceId)
Do I have to call componentWillUnmount()? Please guide me.
Let me know If I am not clear. Thanks.
If you want your component to re-mount when deviceId change you can use the key prop on ComplianceDetails, like this :
<ComplianceDetails key={deviceId} deviceId={deviceId} />

How to access ref element that being conditionally rendered in v-if - Vue

I have an element that being conditionally rendered with v-if="isLogged", if a user is logged in:
<div
v-if="isLogged"
class="chatBlock"
ref="chat"
></div>
I'm trying to get scroll height of the chat reference in a mounted () function - this.$refs.logged.scrollHeight, but it's not possible, because if a user is not logged in, then this div won't be rendered on a mounting stage, so even if a user logs in - it won't work, because mounted stage already passed.
Is it possible to track element appearance in a DOM using watch method?
UPDATE
Added watcher, as Steven suggested below in a mounted ():
this.$store.watch(
(state) => {
return this.$store.getters.isLogged
},
(newValue, oldValue) => {
if (newValue) {
this.chatHeight = this.$refs.chat.scrollHeight
}
}
)
The accepted answer did not work for me. The watch does not guarantee that the element has already been rendered.
To make sure that the element is available, I had to use $nextTick
if (newValue) {
this.$nextTick(function () {
this.chatHeight = this.$refs.chat.scrollHeight
})
}
This will cause the code to be executed after the next DOM update cycle.
Add a watch to isLogged. When it is active, get your chat ref. You will also have to check on your mounted, so put your logic in a common function.
So in your component:
val componentOptions = {
methods: {
checkDiv() {
const chatDiv = this.$refs.chat
if (chatDiv) {
// your code here...
}
}
},
mounted() {
this.checkDiv();
},
watch: {
isLogged(value) {
if (value) {
this.checkDiv()
}
}
}
}
—-
You can also use v-show instead of v-if. That way your element will be rendered but hidden.
Switching to v-show, as suggested by Steven, worked for me. It was actually the better option because v-show is cheap to toggle, unlike v-if, see this answer: https://stackoverflow.com/a/44296275/2544357

Categories