How to get dropdown menu to work on Statelesswidget - redux

I using redux for flutter so every presentation is stateless but i can't get dropdown menu to work property since i can't change it's state to trigger flutter to rebuild the dropdown part when choose value from dropdown.
I trying to implement dropdown menu for this screen.
My code look something like this:
List<String> _suppliers = <String>['Apple', 'Google'];
String _supplier = 'Apple';
...
DropdownButton(
key: _supplierKey,
value: _supplier,
items: _suppliers.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (String newValue) {
_supplier = newValue;
}),
...
I don't know if i implemented it right or anyway to workaround? Any help would be appreciate. Thanks you.

I can see two options here:
Store that value in the state, and dispatch action on every dropdown change.
or
If for some reason you don't want that value in redux state, create a Stateless Widget and store that value inside the State object. You will use setState() method to update it, when you will be ready to send it into state, then just do it the normal way :)

Related

Reset is not clearing fields [redux-form]

I have form with select dropdown, checkboxes and text fields. When I read redux documentation for reseting fields it gives more than 1 way to clear fields - https://redux-form.com/6.0.0-alpha.4/docs/faq/howtoclear.md/
In my situation formvalues are tied to dropdown selection. And I am trying to remove dropdown selection on reset if possible. But that is not possible. So I tried using (c) and (d) ways from the redux document, but they reset it to older values and they do not clear all fields like select drop down do not reset to default selection. The first 2 ways are too complicated for something as simple as resetting.
This is my code where I implemented reset -
const { handleSubmit, reset, errors, submitCallback } = props
//....other code
//....other code
const clearAll = () => {
props.dispatch(reset('myForm'));
};
This resets my form to previous selection and do clear fields. What am I doing wrong?

Double Click Radzen Blazor Tree Items

I am using Radzen Blazor Tree component in a Blazor project. By default the component comes with an event listener for single click on RadzenTreeItem. I am hoping to add functionality such that a single click on a RadzenTreeItem and a double click on a RadzenTreeItem produces different changes to the app. I am thinking of accomplishing this by using a JSInterop for the dblclick event listener, but I know this would require having individual html ids for each RadzenTreeItem and I am not sure how to go about creating unique ids for a RadzenTreeItem since the tree has a dynamic size. My question is how to create unique ids for a RadzenTreeItem if each item is being created in a RenderFragment or is there a better way to allow double click functionality?
Below is an example of the C# RenderFragment that is used to display the RadzenTreeItem:
public static RenderFragment<RadzenTreeItem> TreeDesign = (RadzenTreeItem context) => builder =>
{
builder.OpenComponent<RadzenIcon>(0);
builder.AddAttribute(1, "Icon", "crop_16_9");
builder.CloseComponent();
builder.AddContent(4, context.Text);
};
Below is an example of the html code that is calling the RenderFragment and creating the tree:
<RadzenTree Data="#entries" Change="#OnChange">
<RadzenTreeLevel Template="#TreeDesign" Text="#GetTextForNode" />
</RadzenTree>
5 months old - but I'll give you a shot on how I handle double click years ago in Silverlight.... I created an Observable that would give me an event when there were two clicks within 250MS of each other... this is called a Hot Observable in which the events simply flow by, and when a criteria matches the events, it can raise another event... I can try and dig up the code, as researching for a a double-click event and protection for blazor events.
To add perhaps a bit more clarity - this would listen to the click event you refer to, and if there were two clicks, it would invoke method A, other wise would invoke B for a single click...
A triple click would then become 1 double click, and one single click - but that would depend on the time between the first and thrid event using the Observable...
Maybe it will help someone in the future:
builder =>
{
builder.OpenComponent<RadzenIcon>(0);
builder.AddAttribute(1, "Icon", "crop_16_9");
builder.CloseComponent();
builder.OpenElement(2, "div");
builder.AddAttribute<MouseEventArgs>(3, "ondblclick", RuntimeHelpers.TypeCheck<EventCallback<MouseEventArgs>>(EventCallback.Factory.Create<MouseEventArgs>(this,
(args) => OnDoubleClick(args, context)
)));
builder.AddContent(10, context.Text);
builder.CloseElement();
};
};
private void OnDoubleClick(MouseEventArgs args, RadzenTreeItem item)
{
//
}

UICollectionViewCell custom subview doesn't receive focus

I created custom Poster view so it can be reused in multiple collection view cells (just like TVPosterView in TVUIKit). I add it directly to cell content view with all needed constraints.
The problem is when cell is focused this subview doesn't receive focus update (didUpdateFocus..) so I cannot customize it's focused / unfocused constraints etc. It's odd btw that image view inside is getting floating effect.
In case if I specify cell's preferredFocusEnvironments to return [self.posterView] + super. preferredFocusEnvironments, UI behaves as expected, but the collection view delegate method didSelect not called!
Thanks in advance for any help!
Seems didUpdateFocus not called on all subviews for the focused cell and it's system design. From docs:
After the focus is updated to a new view, the focus engine calls this
method on all focus environments that contain either the previously
focused view, the next focused view, or both, in ascending order. You
should override this method to update your app’s state in response to
changes in focus. Use the provided animation coordinator to animate
changes in visual appearance related to the update. For more
information on animation coordinators, see
UIFocusAnimationCoordinator.
Note: So it means didUpdateFocus will be called first on UICollectionViewCell, than on UIViewController subclasses, in ascending order. For subviews you need to manually register customDidUpdateFocus method that will be triggered in notification update. E.g. to update it's appearance we can use notifications (tvOS 11+), please see the example below.
func customDidUpdateFocus(isFocused: Bool, with coordinator: UIFocusAnimationCoordinator) { /* Custom logic to customize appearance */ }
// Register observer
observerToken = NotificationCenter.default.addObserver(forName: UIFocusSystem.didUpdateNotification, object: nil, queue: .main) { [weak self] (note) in
guard let self = self else { return }
guard let context = note.userInfo?[UIFocusSystem.focusUpdateContextUserInfoKey] as? UIFocusUpdateContext else { return }
guard let coordinator = note.userInfo?[UIFocusSystem.animationCoordinatorUserInfoKey] as? UIFocusAnimationCoordinator else { return }
if let prev = context.previouslyFocusedView, self.isDescendant(of: prev) {
self.didUpdateFocus(isFocused: false, with: coordinator)
} else if let next = context.nextFocusedView, self.isDescendant(of: next) {
self.didUpdateFocus(isFocused: true, with: coordinator)
}
}

Clarity Datagrid column input filter losing focus on first keypress after moving to next page in paginated grid

Using a clarity datagrid version 2.3
Seeing an issue where if the user starts typing into the input field of datagrid column filter, the filter input focuses out automatically as soon as a key is pressed.
Since the datagrid is paginated and server driven, this causes the API to get fired as soon as a
key is pressed after the debounce time.
The automatic focus out of the input field cause the filter to only have a single character and the API gets triggered since the debouce is only 800.
Have looked at clarity github for any reported issues, doesn't look like its reported or anyone having similar issue.
Expected behavior should be the input focus out should not happend until the user moves the cursor away or presses enter, which is when the debounce should kickin after which the api should be called.
HTML:
<clr-datagrid
(clrDgRefresh)= refreshDataGrid($event)>
...
</clr-datagrid>
TS Component:
debouncer = new Subject<any>();
ngOnInit() {
this.debouncer.asObservable().pipe(
debounceTime(800)
).subscribe(state => {
// do something here.. like call an API to filter the grid.
})
}
refreshDataGrid(state) {
this.debouncer.next(state);
}
Any help is appreciated.
Currently I'm hacking my component, to make sure the focus is not lost on the input field until done so by the user.
refreshDataGrid(state) {
const isClrFilterInputField = document.querySelector('.datagrid-filter .clr-input');
if (isClrFilterInputField instanceof HTMLElement) {
isClrFilterInputField.focus();
}
this.debouncer.next(state);
}
This is still not a clean answer, but as far as I have searched, this seems like an issue with clarity datagrid itself, until I hear from someone with a cleaner answer.
Most likely the upgrade version might have this fixed.
Yet to check that.
Unfortunately I think we designed the datagrid to emit the changes on each filter value change with debouncing intended to be done on the app side as consumers see fit.
That said, it is possible to accomplish what you describe. I've implmented a quick and dirty guard based on events but there may be better ways. I'll add code snippets here and a link to the working stackblitz at the end.
You are on the right track with the debouncer. But we don't need to debounce with time, we only need to 'debounce' on certain events.
Instead of debouncing with time, what if we debounce with an #HostListener for clicks on the filter input? (I'll leave it as an exercise for you to implement a HostListener for the focusin event since focusin bubble's up and blur does not). To do that we need:
A Hostlistener that can hear keydown.enter event on the filter input
A guard to prevent requests
A property to store the datagrid state as user enters text
In general the code needs to:
Fetch data when component inits but not after unless directed
Keep track of state events that get emitted from the datagrid
listen to keydown.enter events (and any other events like the filter input focusout - becuase it bubbles up, unlike blur)
Check that the event was generated on a datagrid filter input
dismiss the guard
make the request
re-enlist the guard
Here is a rough attempt that does that:
export class DatagridFullDemo {
refreshGuard = true; // init to true to get first run data
debouncer = new Subject<any>(); // this is now an enter key debouncer
datagridState: ClrDatagridStateInterface; // a place to store datagrid state as it is emitted
ngOnInit() {
// subscribe to the debouncer and pass the state to the doRefresh function
this.debouncer.asObservable().subscribe(state => {
this.doRefresh(state);
});
}
// a private function that takes a datagrid state
private doRefresh(state: ClrDatagridStateInterface) {
// Guard against refreshes ad only run them when true
if (this.refreshGuard) {
this.loading = true;
const filters: { [prop: string]: any[] } = {};
console.log("refresh called");
if (state.filters) {
for (const filter of state.filters) {
const { property, value } = <{ property: string; value: string }>(
filter
);
filters[property] = [value];
}
}
this.inventory
.filter(filters)
.sort(<{ by: string; reverse: boolean }>state.sort)
.fetch(state.page.from, state.page.size)
.then((result: FetchResult) => {
this.users = result.users;
this.total = result.length;
this.loading = false;
this.selectedUser = this.users[1];
// Set the guard back to false to prevent requests
this.refreshGuard = false;
});
}
}
// Listen to keydown.enter events
#HostListener("document:keydown.enter", ["$event"]) enterKeydownHandler(
event: KeyboardEvent
) {
// Use a host listener that checks the event element parent to make sure its a datagrid filter
const eventSource: HTMLElement = event.srcElement as HTMLElement;
const parentElement = eventSource.parentElement as HTMLElement;
if (parentElement.classList.contains("datagrid-filter")) {
// tell our guard its ok to refresh
this.refreshGuard = true;
// pass the latest state to the debouncer to make the request
this.debouncer.next(this.datagridState);
}
}
refresh(state: ClrDatagridStateInterface) {
this.datagridState = state;
this.debouncer.next(state);
}
}
Here is a working stackblitz: https://stackblitz.com/edit/so-60980488

Make ajax call after state change

I want to implement checkbox-based filtering on my page. When I click on checkbox I want to change state and make ajax call based on checked items.
I have created toggleCheckbox(id) action and reducer that adds/removes id from selected items, but I have no idea where should I place ajax call.
Any ideas?
Your component should dispatch the async action, to avoid duplicating the logic for toggling the selected items move it to the async action and change the normal action from toggle to set. Like this:
const toggleCheckbox = id => (dispatch, getState) => {
const items = toggle(id, getState().selectedItems);
dispatch(setSelectedItems(items));
// call API with "items"
};
Network calls are asynchronous, and actions are by default synchronous. They are just plain objets. To handle asynchronous behaviour you need a side-effect library like redux-sagas or redux-thunks. Take a look at https://redux.js.org/docs/advanced/AsyncActions.html and https://redux-saga.js.org

Resources