how to add an event listener in connectCallback - lit-element

I want to wait until elements are rendered in the dom to dispatch an event. I have a lit element that is wrapped around a react element.
In the connectedCallback I have the following
connectedCallback() {
super.connectedCallback();
CommentsManager.register(this);
const event = new Event('ccx-comments-loaded');
window.dispatchEvent(event);
}
in the constructor, I have the following
this.isReadyPromise = new Promise(function(resolve, reject) {
window.addEventListener('ccx-comments-loaded', () => {
resolve(true);
});
});
How can I remove the listener that I created?

I want to wait until elements are rendered in the dom to dispatch an
event.
This looks like you could use an already existing updateComplete method from lit-element lifecycle. It is executed after render and it sounds like you may want to use it instead of having your own events.
You could read more about it here:
https://lit.dev/docs/v1/components/lifecycle/#updatecomplete
This would be a clean and more straightforward way to use lit-element. This way you don't reinvent something existing and your code would be more straightforward and clear for the other developers.

Store a reference to the Event Listener, then remove it in the disconnectedCallback
customElements.define("my-element", class extends HTMLElement {
constructor() {
super();
this.listener = window.addEventListener("click", () => {
this.remove();
});
}
connectedCallback() {
this.innerHTML = `Listening! Click to remove Web Component`;
}
disconnectedCallback() {
// element is no longer in the DOM; 'this' scope still available!!!
window.removeEventListener("click", this.listener);
document.body.append("Removed Web Component and Listener");
}
})
<my-element></my-element>

Related

How to mock a function and expect it to be called?

I am new to react-testing-library and I have been trying to test one function for a long time.
for example, I want to check if when a button is clicked a given function is called and it's throwing errors. so any help would be highly appreciated and if possible share with me any helpful resources.
signin.js
export default class SignIn extends Component {
constructor(props) {
super(props);
this.state = {
};
}
handleClose = (event, reason) => { };
validate = () => { };
change = (e) => { };
onSubmit = (e) => { };
render() {
return (<div>...</div>);
}
}
Full: https://github.com/blaise82/react-testing-library-try/blob/master/src/views/SignIn.js
this is my test
it('should submit form', async () => {
const { getByLabelText, getByText, container, debug } = render(<SignIn />);
const change = jest.fn();
const onSubmit = jest.fn();
const email = getByLabelText('email');
const password = getByLabelText('password');
const submit = getByLabelText('submit');
userEvent.type(email, 'octopusbn#gmail.com');
expect(email.value).toBe('octopusbn#gmail.com');
expect(password.value).toBe('');
expect(change).toHaveBeenCalled();
console.log(password)
await userEvent.click(submit);
expect(onSubmit).toHaveBeenCalled();
});
Full: https://github.com/blaise82/react-testing-library-try/blob/master/src/test/signin.test.js
results
> Expected number of calls: >= 1
> Received number of calls: 0
please let know what I am doing wrong.
Full code on GitHub: https://github.com/blaise82/react-testing-library-try
You can test a function by mocking all that is coming from outside of the component (aka dependencies) like - a prop callback, an external library api etc.
Before starting, let's go through what all functions are in the component.
Going through the component, I can list them as below:
Event handlers on elements [like handleClose, onSubmit, change in the component]
Functions internal to the component which do not interact with the state/functions outside the component [validate]
prop functions/library apis being called [axios.post]
Let's discuss them one by one --
Event handlers &
Functions internal to component not interacting with state/functions outside of the component
==> Event handlers that are attached to elements can safely be expected to get called. You don't need to test them if they are called. Rather, what you should test is the after-effect of them being called. Also the functions like validate
Let's take example of the change function that you are trying to test. This function after being called sets the state and the state gets reflected into the form elements. We can assert values of the form elements with a helper like this.
prop functions/library apis being called [axios.post]
==> These functions can be mocked and tested for the number of calls/parameters they are called with.
https://jestjs.io/docs/en/mock-functions.html#mocking-modules
In addition to the snippet of mocking jest as given in the link above, in your case -
axios.post.toHaveBeenCalledWith(expectedParms);
Also you can make it return results/errors you want and test respective component behaviour.
Hope you find this helpful. Cheers!
I think this is because you are not actually passing in your mocked functions to the component. You're just instantiating two constants that happen to have the name of the functions you're trying to watch, but are not actually being used anywhere in your component.
It sounds like you want to spy on your component's internal functions to see that they've been called.
Here's something of an example (not tested) based on a post (linked below) that might help you.
describe('spying on "onSubmit" method', () => {
it('should call onSubmit when the button is clicked', () => {
const wrapper = shallow(<SignIn />);
const instance = wrapper.instance();
jest.spyOn(instance, 'onSubmit');
wrapper.find('button').simulate('click');
expect(instance.onSubmit).toHaveBeenCalled();
});
});
Post: https://bambielli.com/til/2018-03-04-directly-test-react-component-methods/#spying-on-incrementcounter

unsubscribe to an Observable created by of

When I create an observable and I am done with it I unsubscribe it directly
const data$ = this.httpClient.get('https://jsonplaceholder.typicode.com/todos/1').subscribe(res => {
console.log('live', res);
data$.unsubscribe(); // <---- works fine
});
But say if I create an Observable using of and try to do the same
const obs$ = of(1).subscribe(e => {
console.log('test', e)
obs$.unsubscribe(); // <--- Problem while creating Observable by of
});
Whats different between these 2 observables?
Your code should be import Subscription and unsubscribe in ngOnDestroy
import { Observable, Subscription, of } from "rxjs";
private subscription$: Subscription;
this.subscription$ = of(1).subscribe(e => {
console.log('test', e)
});
ngOnDestroy() {
this.subscription$.unsubscribe();
}
Update: What I understand is http request is an observable that potentialy have incoming value in the future and of simply create a list of observable
And from #cartant comment
of completes synchronously, so you are attempting to call
obs$.unsubscribe before the assignment to obs$ has been made.
If you have only one observable in your component that would be the easiest scenario for unsubscribing by the following way:
ngOnDestroy() {
this.subscription$.unsubscribe();
}
the more complex scenario is having multiple observables, at that moment you will not to push each observable while subscribing in subscriptions: Subscription[] and while destroying do unsubscribe all added subscriptions in the array ngOnDestroy(){
this.subscriptions.forEach(sub => sub.unsubscribe());
}
or you can use that npm package
For ensuring unsubscription in a component, I would recommend creating a Subject which emits in ngOnDestroy() like this:
destroy$ = new Subject<boolean>();
...
ngOnDestroy() {
this.destroy$.next(true);
}
And adding a takeUntil on each Observable in the component:
myObs$.pipe(
takeUntil(this.destroy$),
tap(stuff => doStuff())
).subscribe();
This way you avoid polluting things with loads of unnecessary Subscription variables.

what is the best method to multi request with callback or promise on node.js

I have a situation. I use Node.js to connect to a special hardware. let assume that I have two functions to access the hardware.
hardware.send('command');
hardware.on('responce', callback);
At first, I made a class to interface this to the application layer like this (I write simplified code over here for better understanding)
class AccessHardware {
constructor() {
}
updateData(callback) {
hardware.on('responce', callback);
hardware.send('command');
}
}
Now, the problem is that if there are multiple requests from the application layer to this access layer, they should not send multiple 'command' to the hardware. Instead, they should send one command and all of those callbacks can be served once the hardware answer the command.
So I update the code something like this:
class AccessHardware {
constructor() {
this.callbackList = [];
hardware.on('responce', (value) => {
while (this.callbackList.length > 0) {
this.callbackList.pop()(value);
}
});
}
updateData(callback) {
if (this.callbackList.length == 0) {
hardware.send('command');
}
this.callbackList.push(callback);
}
}
Of course, I prefer to use promise to handle the situation. so what is your suggestion to write this code with promise?
Next question, is this approach to make a 'list of callbacks' good?
I prefer to use promise to handle the situation. So what is your suggestion to write this code with promise?
You'd store a promise in your instance that will be shared between all method callers that want to share the same result:
class AccessHardware {
constructor(hardware) {
this.hardware = hardware;
this.responsePromise = null;
}
updateData() {
if (!this.responsePromise) {
this.responsePromise = new Promise(resolve => {
this.hardware.on('responce', resolve);
this.hardware.send('command');
});
this.responsePromise.finally(() => {
this.responsePromise = null; // clear cache as soon as command is done
});
}
return this.responsePromise;
}
}
Btw, if hardware is a global variable, there's no reason to use a class here.
Is the current solution to make a 'list of callbacks' good?
Yes, that's fine as well for a non-promise approach.

Deselection fabric.js object event

I am trying to execute some code every time a specific fabric object is "deselected". Is there any deselection event I can handle? I already have a function for when the object is selected, via the selected event, but have not found any documentation about the deselected one. At the canvas level I have the selection:cleared and selection:created events, but nothing for the deselection either.
Cheers,
Gonzalo
Use the before:selection:cleared event and get the active object or group. After that you can check if it corresponds to your specific fabric object.
canvas.on('before:selection:cleared', function() {
var clearedObject;
if(typeof(canvas.getActiveObject()) !== 'undefined') {
clearedObject = canvas.getActiveObject();
}
else {
clearedObject = canvas.getActiveGroup();
}
//do stuff with the deselected element if it is the specific one you want.
});
Just to let you all know that the newest versions of Fabric.js include a deselected event for the Object class. The only thing you need to do now is:
var aFabricObject = <create your fabric object>
aFabricObject.on('deselected', function (options) {
// your code here
});
Update for the upper answer:
The 'deselected' event fires a async method, so you can not get 'options.deselected' immediately.
var aFabricObject = <create your fabric object>
aFabricObject.on('deselected', function (options) {
console.log(options.deselected) // output undefined
setTimeout(() => {
console.log(options.deselected) // output the correct target
}, 0)
});

Define a global ready function for every page in WinJS

My WinJS app uses the single navigation model. There is some common code that I would like to apply to every page in the app. Instead of placing the code in each page's ready function, I would like to be able to able to define a "global" ready function that will be executed when a page's ready event is fired. Any ideas?
you can define a Mixin object with utility function used for all pages.
utils.js:
PageMixin = {
ready: function ready(element, options)
{
this.element = element;
this.options = options;
this.initialize();
this.onready();
},
initialize: function initialize()
{
// write common initialize code here
}
};
page.js:
var Page = WinJS.UI.Pages.define('/pages/mypage/page.html',
{
onready: function onready()
{
// page specific initialization code here
}
});
// this will make all PageMixin util methods available on Page.
WinJS.Class.mix(Page, PageMixin);
refer WinJS.Class.mixin for details.

Resources