How to unlisten MDCDialog event - material-components

I have a small function which listen to MDCDialog:closing.
The problem is, each time I run this function, it add a new listener.
So, I need to remove this same listener once I'm done using it.
So far, this is what I did:
function confirm() {
mdcAlert.open();
// start listening
mdcAlert.listen("MDCDialog:closing", function(event) {
{... execute what need to be done ...}
// stop listening (not working)
mdcAlert.unlisten("MDCDialog:closing");
});
}
Do you happen to know how to use unlisten?
I can't figure out how to use it in the doc:
https://material.io/develop/web/components/dialogs/
https://pub.dev/documentation/mdc_web/latest/mdc_web/MDCComponent/unlisten.html

Found the solution.
Had to pass a variable with a function inside.
function confirm() {
let eventListener=function(event) {
{... execute what need to be done ...}
//Unlisten after execution
mdcAlert.unlisten("MDCDialog:closing", eventListener);
};
mdcAlert.open();
mdcAlert.listen("MDCDialog:closing", eventListener);
}

Related

Adding Click Event Listener to Adobe Data Layer in React

I'm just starting to enter the world of Adobe Analytics. I'm working in React with Typescript and I am trying to leverage the adobe data layer to send information to Adobe Launch. I've been able to successfully use the adobe push function (i.e. window.adobeDataLayer.push({ test: 'test succeeded' })) and can both see that in the console via window.adobeDataLayer.getState() and ran a simple test to confirm it made its way to Adobe Launch.
However, when it comes to adding an event listener, I'm stumped. I attempted to follow Adobe's Documentation and came up with the following (doStuff() was just to confirm that eventListeners were working as expected, which they do):
function myHandler(event: any): void {
console.log("My handler was called")
}
function doStuff() {
console.log('do stuff was called')
}
function adobeAnalyticsTest(): void {
console.log(' adobeAnalyticsTest function called')
window.adobeDataLayer = window.adobeDataLayer || []
window.adobeDataLayer.push({ test: 'test succeeded' })
window.addEventListener('click', doStuff)
window.adobeDataLayer.push(function (dl: any) {
dl.getState()
dl.addEventListener('click', myHandler)
})
}
useEffect(() => {
adobeAnalyticsTest()
}, [])
Looking at window.adobeDataLayer, I couldn't see anything that seemed to indicate there was a click event listener (although this could be ignorance on my part) nor was 'My Handler was called' ever logged to the console. Does anyone have any ideas as to what I'm doing wrong or know how to tell when it's working correctly?
At face value, it looks like you don't have anything in your code that actually calls adobeAnalyticsTest().
Also, the listener you attach to dl doesn't listen for DOM events like clicking on something in window (like your window.addEventListener line); it listens for payloads pushed to adobeDataLayer where the passed event property value matches what you are listening for.
For example, put adobeDataLayer.push({'event':'click'}) in your js console you should see "My handler was called".
Think of it more like subscribing to a CustomEvent (because that's what it is, under the hood), rather than a native DOM event.

Not able to trigger function from event

I am not a skilled react programmer but still hope someone would care to explain what I am missing:
What I want
I would like to change accounts in Metamask, detect the "accountsChanged" event, and trigger the testFunction.
What works
I am able to trigger the testFunction by clicking the test function button.
I can detect account change (for some reason it is detected around 5 times every time I change).
What does not work
I am not able to trigger the testFunction upon account change and get the message TypeError: this.testFunction is not a function
Suspect there is something fundamental about react I am missing here...Thanks for all replies!
class App extends Component {
...
componentDidMount = async () => {
...
};
testFunction = async =>{
console.log("triggered the test function");
};
render() {
window.ethereum.on('accountsChanged', function (accounts) {
console.log("account change detected");
this.testFunction(); --> this is not working
});
return (
<div className="App">
<button type="button" onClick={this.testFunction}>test function</button>
</div>
);
}
}
You need to convert your normal function to arrow function. Because normal function derives this from the object which is calling it, but arrow function derives it's this from surrounding scope, hence in arrow function this will point to your class and will have access to the methods.
window.ethereum.on('accountsChanged', accounts => {
Also, you can continue using normal function, but in that case you can store the this in some other variable like that' or 'self and use it inside the normal function to call the methods of the class.
let that = this;
window.ethereum.on('accountsChanged', function(accounts){
that.testFunction() //this will work
I struggled to update the component of my app when an account was changed using MetaMask. What I did was what Vivek suggested: create a reference of this and then handle the callback. At the end my function using etherjs and the same event of metamask (ethereun.on('accountsChanged'..was this
const here = this
provider.provider.on('accountsChanged', function (accounts) {
console.log('Account changed!!')
here.currentAccount = accounts[0]
})
This code also work with Vue

useState not updating correctly with socket.io

I am pulling data via socket.io but when listening for incoming messages from the server my state is not updating correctly.
I can see the data is being pulled correctly from the socket (50 reqs peer second) but setQuotes just replaces the existing item with the new item returned from the server (so my state always has a length of one).
const [quotes, setQuotes] = useState([])
const subscribe = () => {
let getQuote = 'quote.subscribe';
socket.emit(getQuote, {});
socket.on('listenAction', function (msg) {
setQuotes([...quotes, msg]) // This just replace the entire state instead of adding items to the existing array
});
}
Subscribe // Open web socket stream
You need to move the listener outside of the subscribe function.
Since it is a sideEffect you should wrap it in React.useEffect
It's also a good idea to use functional setstate to read previous values.
React.useEffect(() => {
socket.on('listenAction', function (msg) {
setQuotes((quotes) => [...quotes, msg])
});
}, []);
In your example you use setState like this
setQuotes([...quotes, msg])
And every time you get message, javascript engine tries to find "quotes" variable in scope of this function
function (msg) {
It can not find it here and move to the scope, where this function was defined ( scope of component function).
For every function call, there is new scope. And react calls component function for each render. So, your function with "msg" in arguments, where you use setQuotes, every time uses "quotes" state from first render.
In first render you have an empty array.
Then you have [...firstEmptyArray, firstMessage]
Then you have [...firstEmptyArray, secondMessage]
Then you have [...firstEmptyArray, thirdMessage].
Probably, you can fix it if you will use setQuotes like;
setQuotes(oldQuotes => [...oldQuotes, msg]);
In this way it will use previousValue for calclulating new one.
PS. Be aware of not to call your subscribe function directly in each render and put it in useEffect with correct dependency array as second argument.
You can use the concat func over here
setQuotes(prevState => prevState.concat(msg))

Accessing this object in componentdidmount

I'm having a problem with accessing/triggering functions from componentDidMount in React. All this references seem to be undefined even if I try binding the method in the constructor like this:
this.componentDidMount = this.componentDidMount.bind(this);
Here is a part of the code; I'm accessing events on leaflet maps and printing map boundaries to the console - which works fine (and that's the reason I need to use componentDidMount)
componentDidMount(){
let mapInst = this.refs.map.leafletElement;
mapInst.on('moveend', function () {
console.log(mapInst.getBounds())
});
mapInst.on('dragend', function () {
console.log(mapInst.getBounds())
});
}
Now I would like to pass those boundaries to state parameters or launch a function on callback to a parent element.
updateParent = (newBounds) => {
this.props.parentCallback({'bounds': newBounds});
}
However whatever construction I try, any function in higher scope is always undefined. It seems I cannot access neither updateParent(mapInst.getBounds()) nor this.updateParent(mapInst.getBounds()) from within componentDidMount.
Does anybody have any idea what the optimal construction in such cases is?
Full code for reference: https://pastebin.com/gQqazSCs
I think you want to use leaflet's whenReady callback.
handleMapReady = ({ target }) => {
this.setState({ leafletMapElt: target });
};
...
<Map whenReady={this.handleMapReady}>...</Map>
I don't think the map is guaranteed to be in a "ready" state in componentDidMount
Make callback function of mapInst.on to arrow function and then try to access updateParent like this mapInst.on('moveend', ()=> { this.updateParent(mapInst.getBounds()) });
Arrow function will take its surrounding this

Reactjs function not being called

I'm implementing the Facebook SDK on my react project, however, I am new to React and I still don't grasp some concepts. I'm calling handleFBLogin when a user clicks on a button. This function then calls checkLoginState to continue my code's logic. I've already bound checkLoginState in the constructor using:
this.CheckLoginState = this.checkLoginState.bind(this);
I call this function on handleFBLogin, but checkLoginState doesn't seem to be called. I can see the yes on my console:
handleFBLogin() {
console.log("yes")
this.checkLoginState;
}
Here's the checkLoginState function:
checkLoginState(){
console.log("checloginstate")
window.FB.getLoginStatus(function(response) {
console.log(response);
this.statusChangeCallback(response);
}.bind(this));
}
Why isn't it being called?
It's possible you think to call the function without using parentheses as you do in the event like onClick={this.yourMethod}. It works because the react will handle it internally.
But calling a function from a method to another, you need to call the function using parentheses:
this.checkLoginState()
But wait! this will be undefined here if have not bind this. So, bind this inside your constructor:
this.handleFBLogin = this.handleFBLogin.bind(this)
Alternatively, you may use public class method:
handleFBLogin = () => {
this.checkLoginState()
I think it is type error. You forgot to add '()' for calling a function.
handleFBLogin() {
console.log("yes")
this.checkLoginState();
}
inside handleFBLogin() try () => this.checkLoginState(); . You need the parenthesis to invoke the method.

Resources