TNG / ngqp

Declaratively synchronize form controls with the URL
https://tng.github.io/ngqp
MIT License
81 stars 8 forks source link

Programmatically delete/remove/reset queryForms and queryParams #172

Closed verfault closed 4 years ago

verfault commented 4 years ago

Hello. Could you give a hint:

  1. Is here any way to do full reset of a QueryForm programmatically? (same as Angular Reactive Forms' reset() method).
  2. What method should I call to unsync URL from QueryForm programmatically? I mean I want to use a method of a queryParam like clear() to clear my input's data from URL and unsync it from QueryForm in my .ts file.

Thanks.

Airblader commented 4 years ago

Hi!

reset can be essentially mimicked using setValue({})¹ since ngqp has no notion of pristine/dirty and no nesting, so all that reset would do is clear out the values anyway. The only caveat here would be emptyOn handling. Given that in the Forms API reset doesn't "unbind" the form either, is there anything in particular you'd be missing doing this?

As for the "unsynchronizing" part: Could you outline the use case in which you would need this?

¹ We should probably allow setValue(null), which I don't think we currently do. Edit: PR opened for this.

Airblader commented 4 years ago

I mean I want to use a method of a queryParam like clear() to clear my input's data from URL and unsync it from QueryForm in my .ts file.

If you're talking about taking a specific QueryParam out of the QueryParamGroup, you can do so using QueryParamGroup#remove. This will remove it from the synchronization process.

verfault commented 4 years ago

Thank you for a quick response!

To be honest, mimicked methods and "emtpy-on-bottle-neck" might be tricky and unintuitive withoup deep knowledge so i assume that adding a hint to the docs would be a great idea, wouldn't it?

My bad that I've given an abstract situation. The case:

  1. I have a queryGroup with one queryParam which is q for some searching stuff.
  2. For example, my markup is right below:
    <div class="search">
    <form
    class="search__form"
    [queryParamGroup]="queryGroup"
    >
    <label for="search-input">Some stuff</label>
    <input
      name="query"
      type="text"
      id="search-input"
      queryParamName="queryText"
      #input
    >
    <button class="visually-hidden" type="submit">Accept</button>
    </form>
    </div>
  3. On popup's close (OnNgDestroy) i need to delete q param from URL and clear the form.
  4. Code of destroying and definition:

    queryGroup = this.qpb.group({
    queryText: this.qpb.stringParam('q')
    });
    
    ngOnDestroy() {
    // ... 
    
    this.queryGroup.setValue({});
    this.queryGroup.remove('queryText')
    }
  5. And after many attempts it's still not working - 'q' from URL doesn't dissapear.

Probably (exactly) I'm doing something wrong. Is there an option to delete queryParams from URL? programmatically or not. Thanks.

Airblader commented 4 years ago

To be honest, mimicked methods and "emtpy-on-bottle-neck" might be tricky and unintuitive withoup deep knowledge so i assume that adding a hint to the docs would be a great idea, wouldn't it?

Yeah, definitely; I'm also not against adding synonym methods for clarity (like reset() = setValue(null)). We just need to make sure this is what we actually need.

Thanks for providing the example, I appreciate it. If the component gets destroyed you don't need to call remove in the end. Calling setValue({}) does work in general, see this example. However, in your case it doesn't work because the service gets destroyed before the last setValue call propagates, see a toy example here.

A workaround for this can be seen here, which is to manually remove the query params through the router directly:

public ngOnDestroy() {
  this.router.navigate([], {
    queryParams: {
      q: undefined,
    },
    queryParamsHandling: 'merge',
    replaceUrl: true,
  });
}

Obviously this is far from ideal, but it should at least unblock you. Given your use case I think it might make sense to have a feature on ParamGroup level to remove all managed parameters on destroy, something like

this.qpb.group({
  queryText: this.qpb.stringParam('q'),
}, {
  clearOnDestroy: true,
})

That should also be a relatively easy feature to add, I think. We could add a similary thing to remove:

this.paramGroup.remove('queryText', {
  clear: true,
});

though for your case you wouldn't actually need that, and I think this can be treated as separate features.

Would the above solution (and intermediate workaround) work for you?

Airblader commented 4 years ago

@hifull I've implemented the solution described above in PR #174 now. Please let me know if this would work for you and we can merge it and create a release.

verfault commented 4 years ago

@Airblader Hello! I'm sorry about making you wait for a long time. I had been burning with other tasks without any break for a cup of coffee before I finally came here to check you answer. I'm very grateful that you've implemented the feature that fast.

The workaround works like a charm. So I think your suggestion is really amazing and will cheer some devs if they're stuck one day with the same problem.

Peace!

Airblader commented 4 years ago

Thanks for your suggestion and detailed explanation! This is now released in @ngqp/core@1.1.0.