ExtJS menu checkItem: how to prevent item check event in certain circumstance? - events

for a menu checkItem, when user clicks at it, by default it will trigger checkchange; i am wondering how to, if a certain case is met, not change its check status after clicked, in other words, stop this event chain.
I tried following codes, but not work:
listeners: {
'click': function(item, evt) {
if(1) { //verify whether that certain case
evt.stopEvent(); //since click_event is triggered before setChecked()/checkChange, I thought this may stop its going further...
alert('case met!');
}
},
checkHandler: function(item, checked) {
//...
}

You can listen to the beforecheckchange event. Here it is in the docs.
As per the docs, just apply your conditional logic and if it doesn't pass, return false from the handler.
E.g.:
listeners: {
'beforecheckchange': function(item, checked) {
if(!1) { // or whatever your conditional logic is
return false;
}
},
}

Related

Svelte - on:event listener removal

I'm wondering whether assigning undefined to an element's event, i.e. on:mousemove prevents a memory leak the same as removeEventListener does, or at least should not be a concern long term. I've checked with getEventListeners on chrome, and it's there with the on:mousemove approach, but I'm not sure whether I should worry about this and use the more verobse approach with custom actions.
I have a Dropdown inside a Container. On moving the mouse over the container, I want to change the Dropdown's position.
My initial approach was writing a custom use:containerMouseMove action, that took Dropdown's visible as a dependency, and removed the event listener from the container, when the Dropdown became invisible.
Dropdown.svelte:
use:mousemoveContainer={{ container, destroyOn: !visible }}
on:mousemove_container={(e) => {
if (mouseTrack) {
[x, y] = calcCoordinates(e, container);
}
}}
Action definition:
type Deps = { container: HTMLElement; destroyOn: boolean };
export const mousemoveContainer = (node: HTMLDivElement, deps: Deps) => {
const handleMouseMove = (e: MouseEvent) => {
node.dispatchEvent(new CustomEvent('mousemove_container', { detail: e }));
};
return {
update(deps: Deps) {
if (!deps.destroyOn) {
deps.container.addEventListener('mousemove', handleMouseMove);
}
if (deps.destroyOn) {
deps.container.removeEventListener('mousemove', handleMouseMove);
}
}
};
};
Then I learned about export const function as a way to communicate between parent and child, and it simplifies the code. But I'm not sure if there's not a memory leak right now.
on:mousemove={dropdown.getVisible() ? dropdown.onContainerMouseMove : undefined}
onContainerMouseMoveis the callback inside on:mousemove_container.
on:event listeners are removed automatically when the component is unmounted.
Within actions, one should return an object with a destroy() function and unsubscribe from events there. The function will be called when the element with the action on it is removed.

How do I do this via RxJs?

I have a autocomplete control that triggers a onAutoCompleteSearch() after a debounce where I retrieve results from the server. However, if the user enters text and hits enter (key code 13) then a signal should be raised that will cancel the next invocation of an autocomplete. Since this is a 3rd party control I don't have control over the invocation of onAutoCompleteSearch() that occurs after a set debounce time.
I am using a Subject to do the signalling:
private cancelAutoComplete$ = new Subject<boolean>();
If user hits enter key:
onKeyUp(e) {
if (e.keyCode === 13) {
this.cancelAutoComplete$.next(true);
this.fireExecuteSearch(); // fire full search
} else {
this.fireSearchChange(); // trigger user input change
}
}
When an autocomplete is to be executed:
onAutoCompleteSearch(e) {
console.log('starting autocomplete!');
this.cancelAutoComplete$
.first()
.defaultIfEmpty(false)
.subscribe(c => {
if (c) {
console.log('autocomplete cancelled!');
} else {
console.log('execute the autocomplete!');
this.executeAutoComplete.next(e.query);
}
});
}
the above does not quite work... what I wish to do is check the cancelAutoComplete stream for an element, if one exists then take it off the stream, if the cancel flag is true then abort the autocomplete. If there isn't an element then return a default element of false so I can continue with the autocomplete.
How can I accomplish this? Basically if there is an cancel signal pending from the onKeyUp -> keycode 13 event I want to abort the call, if not continue.
I know I can use a simple boolean to track this but wanted to know how to do it via RxJs Subjects.
Firstly I'd make cancelAutoComplete$ a BehaviorSubject initialised to false. Send it false whenever the keyCode is not 13:
private cancelAutoComplete$ = new BehaviorSubject<boolean>(false);
onKeyUp(e) {
if (e.keyCode === 13) {
this.cancelAutoComplete$.next(true); // prevent autocomplete
this.fireExecuteSearch();
} else {
this.cancelAutoComplete$.next(false); // allow autocomplete
this.fireSearchChange();
}
}
Then I'd use the takeUntil operator as part of your executeAutoComplete stream as follows:
onAutoCompleteSearch(e) {
this.executeAutoComplete.next(e.query);
}
this.executeAutoComplete
.switchMap(query => this.backend.fetchAutoCompleteResults(query).takeUntil(
this.cancelAutoComplete$.filter(c => c === true)
))
.subscribe(...);
I've assumed your backend api is named this.backend.fetchAutoCompleteResults - the takeUntil will abort it if cancelAutoComplete$ is initially true or becomes true while the call is in flight.

Will react fire a state change if the prev and next state are the same?

On my state change handler should I need to do the following:
deviceSize = ...
this.setState((prevState) => {
if (prevState.deviceSize != deviceSize) {
return {
deviceSize
}
} else {
return null
}
})
Or is the following enough
this.setState((prevState) => {
return {
deviceSize
}
})
My concern is if I return something it will do some UI update.
You are wrong here. setState never check for values. When it is called, it just re-render view.
To check component should re-render or not,check shouldComponentUpdate() method.
`shouldComponentUpdate(nextProps, nextState)` {
1. it is triggered before the re-rendering process .
2. It tells render() method should be called or not.
3. If nothing changed, you can avoid re-render by returning false.
}
I would not go this route at all. You should not be calling setState unless you know its time to setState.
You should read the docs on setState
Use componentDidUpdate to know when to call setState. Like the docs say
Generally we recommend using componentDidUpdate() for such logic
instead.
For instance
componentDidUpdate(prevProps, prevState) {
if (prevState.something !== something) { // you can compare previous state or props with current state or props
this.setState({something: something});
}
}
notice that setState is only called when you actually want to call it

Event each time component becomes visible

Is there a way in Angular2 to have an event fired when my component becomes visible?
It is placed in a tabcontrol and I want to be notified when the user switches. I'd like my component to fire an event.
What I finally did (which is not very beautiful but works while I don't have a better way to do it...) is to use the ngAfterContentChecked() callback and handle the change myself.
#ViewChild('map') m;
private isVisible: boolean = false;
ngAfterContentChecked(): void
{
if (this.isVisible == false && this.m.nativeElement.offsetParent != null)
{
console.log('isVisible switched from false to true');
this.isVisible = true;
this.Refresh();
}
else if (this.isVisible == true && this.m.nativeElement.offsetParent == null)
{
console.log('isVisible switched from true to false');
this.isVisible = false;
}
}
There is no such event, but if you're using a tab control, the proper way to do this would be to create a tab change #Output for your tab control if it's custom, otherwise, most tab controls (like ng-bootstrap) have some tab change event as well.
If your component has to be aware of this, you can use this tab change event to detect which tab is visible, and if you know which tab is visible, you also know if your component is visible or not. So you can do something like this:
onTabChange(event) {
this.currentTab = /** Get current tab */;
}
And then you can send it to your component itself if you have an input:
#Input() activated: boolean = false;
And then you can apply it with:
<my-component [activated]="currentTab == 'tabWithComponent'"></my-component>
Now you can listen to OnChanges to see if the model value activated changed to true.
You can also refactor this to use a service with an Observable like this:
#Injectable()
export class TabService {
observable: Observable<any>;
observer;
constructor() {
this.observable = Observable.create(function(observer) {
this.observer = observer;
});
}
}
When a component wishes to listen to these changes, it can subscribe to tabService.observable. When your tab changes, you can push new items to it with tabService.observer.next().
You can use the ngAfterViewInit() callback
https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
Update
The new Intersection Observer API can be used for that
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
See also https://stackoverflow.com/a/44670818/217408
For those watching at home, you can now use ngAfterContentInit() for this, at least on Ionic anyway.
https://angular.io/guide/lifecycle-hooks
Best way to work around this limitation of Angular is to use a shared service that provides a Subject your component can subscribe to. That way new values could be pushed onto the Observable and the components which subscribe get the newest data and can act accordingly.
Fyi: The difference between a normal Observable and a Subject is that a Subject is multicast whereas an Observable could only be subscribed to by one Subscriber.
As a small example I show you a possible implementation of a shared-service and following the subscription inside the component that needs this new data.
Shared-service:
// ...
private actualNumberSubject = new Subject<number>()
public actualNumber$ = this.actualNumberSubject.asObservable()
/**
* #info CONSTRUCTOR
*/
constructor() {}
/**
* #info Set actual number
*/
setActualNumber(number: number) {
this.actualNumberSubject.next(internalNumber)
}
// ...
Push new value onto the subject from anywhere where shared.service is imported:
// ...
this.sharedService.setActualNumber(1)
Subscribe to sharedService.actualNumber$ in component to process/display that new data:
// ...
this.sharedService.actualNumber$.subscribe(number => {
console.log(number)
// e.g. load data freshly, etc.
})
// ...
I have the same purpose and cannot get a satisfy approach to it. The first answer will call so many times.
There is a compromised way I used, of course, not elegant either.
In parent component, I set a method:
parentClick() {
setTimeout(() => {
// TO-DO
This.commonService.childMethod();
}, time);
}
Maybe the method not accurate in time, but in some way, you reach the destiny.

DataTable validation: ColumnChanging vs RowChanging

Here is my form code which saves dataset:
salesInvoiceBindingSource.EndEdit();
salesInvoiceLineBindingSource.EndEdit();
if (invoiceDataSet.HasChanges() && !invoiceDataSet.HasErrors)
{
this.tableAdapterManager.UpdateAll(this.invoiceDataSet);
}
I've noticed that if I put validation code in ColumnChanging event:
void SalesInvoiceDataTable_ColumnChanging(object sender,
System.Data.DataColumnChangeEventArgs e)
{
if (e.Column.ColumnName == "CustomerCode")
{
if (string.IsNullOrWhiteSpace((string)e.ProposedValue))
e.Row.SetColumnError("CustomerCode", "Required");
else
e.Row.SetColumnError("CustomerCode", string.Empty);
}
}
}
then invoiceDataSet.HasErrors is false even when CustomerCode is empty string, because the event fires after dataset is saved. But if I put validation code in RowChanging event, it fires before UpdateAll() method; so it works fine. Why is it that? I'd like to use ColumnChanging event, not RowChanging event.
EDIT: This happens to new records, which were created by:
salesInvoiceBindingSource.AddNew();
Most operations that add or delete rows do not raise the ColumnChanged and ColumnChanging events

Resources