1

I'm trying to build a url step by step but I can not do it. I explain the situation: I realize an application for booking a coach online (step by step) with a angular material stepper.

Step 1: will be to go to myapp/booking/coachs url (for a list of coaches).

Step 2: grab the coach's id and add it to the url (myapp/booking/coachs/1).

Step 3: choose a date (myapp/booking/coachs/1/date/2018-07-13), then choose a time available -> (myapp/booking/coachs/1/date/2018-07-13/hour/9)

I can manage to get the id of the coach, etc., but I can not build the url step by step

Can someone guide me in the right direction to do that, please?

3
  • Your question is unclear. What do you mean by "build the url step by step" ? Maybe you could share a bit of code to let us understand what you've done so far. Commented Jul 13, 2018 at 10:05
  • Step by step, in the sense that when I select a coach, I go to step 2 and the url goes from myapp/booking/coach to myapp/booking/coach/2 Then when I select the date in step 2 the url goes to myapp/booking/coach/2/ date/2018-07-13. I will gradually add information in the url Commented Jul 13, 2018 at 10:09
  • router.navigate(['./childURL']) ? Commented Jul 13, 2018 at 10:19

3 Answers 3

2

If you hookup the MatStepper to a FormGroup and then set the url based on the form's current value you can get the intended functionality:

  // setup controls
  coachIdControl = new FormControl(null, [Validators.required]);
  dateControl = new FormControl(null, [Validators.required]);

  formGroup = new FormGroup({
    coachId: this.coachIdControl,
    date: this.dateControl
  });

To bind the form to the url and vice versa you can:

// take values from the url and use to populate the form and set current step
// (you can also use queryMap to use /coach/:id/date/:date url)
// if the user refreshes the page, the form will repopulate from the query
this._route.queryParamMap.subscribe(query => {

  if(query.has('coachId') && this.coachIdControl.value !== query.get('coachId')){
    this.coachIdControl.setValue(query.get('coachId'));
    this.matStepper.selectedIndex = 1;
  }

  let date = moment.isMoment(this.dateControl.value) ? this.dateControl.value.format('YYYY-MM-DD') : null;

  if(query.has('date') && date !== query.get('date')){
    this.dateControl.setValue(query.get('date'));
    this.matStepper.selectedIndex = 2;
  }
  this.formGroup.updateValueAndValidity();
});

// if the form changes, update the query params in the url
this.formGroup.valueChanges.subscribe(value => {
  this._router.navigate(['.'], {queryParams: {
    coachId: value.coachId,
    date: moment.isMoment(value.date) ? value.date.format('YYYY-MM-DD') : null
  }});
});

The full example is here: StackBlitz - angular-material-routed-stepper

Update: Reset Steps

To remove url query values when stepping back you can listen for the selectionChange event and reset the values for steps that come after the selected step:

this.matStepper.selectionChange.subscribe((event: StepperSelectionEvent) => {


  switch(event.selectedIndex){
    case 0:
      this.dateControl.setValue(null);
    case 1:
      this.confirmControl.setValue(null);
  }

});

(Since the switch statements falls through, every step after the selected step will be reset.)

setValue will, in-turn, emit the valueChanges event which will update the url query.

The above Stackblitz is updated with this functionality.

Sign up to request clarification or add additional context in comments.

3 Comments

Wow, this is awesome, thank you so much , I could not hope better @christiaan
This type of binding between the Router and FormGroup is useful for tables/indexes, stepped forms, etc. Glad I could help.
Hello @christiaan , I have another question. How I can reset the url on previous step ? If I'm on step 2 (booking?coachId=1&date=2018-07-02) and I'm going on step 1, I'd like to reset the date and have something like -> booking? CoachId = 1. Thank you !
1

You could try adding a shared service to the components that can hold onto the URL and add to it as you go through each step. Something like this:

export class URLService {

  private URL: string[] = [];

  public addToURL(segment: string): void {
    this.URL = [ ...this.URL, segment ];
  }

  public retrieveURL(): string {
    return this.URL.join('/');
  }

}

So inject the URLService into any component you are using to build the URL and each time you have a new item to add, call urlService.addToURL('item'). Then when you are ready for your full URL, call urlService.retrieveURL() to get a string that you can use.

1 Comment

Thank you @lordchangellor, that's exactly what I was looking for!
1

I create a first version, but you should change the normal input text for calendar input on case of date and selector for coachs ID's:

https://stackblitz.com/angular/oyxooylkovag

cheers!

1 Comment

Thank you @Daniel, this problem was secondary but it will help me to move forward :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.