3

I am prepared to spend the day researching this, but I hope you guys have answer as I think otherwise this would be an all day thing.

I have the following variables

  inputCity;
  inputGuestNumber;
  inputCapacitySelected;
  inputCuisineSelected;
  inputPrivacySelected;
  inputVenueTypeSelected;
  inputAmenitiesSelected;
  inputNeighborhoodSelected;

these variables may or may not be populated or defined depending on what information a user enters into a form.

I have the current router set up:

onSubmit(){
    this.router.navigate(['/venue-list',
    this.inputCity], {queryParams:{guestCount: this.inputGuestNumber, countOption: this.inputCapacitySelected,
    cuisineSelected:this.inputCuisineSelected, privacySelected:this.inputPrivacySelected,
      venueTypeSelected: this.inputVenueTypeSelected, amenitiesSelected: this.inputAmenitiesSelected,
    neighborhoodSelected: this.inputNeighborhoodSelected}

  });

I set it up this way hoping that if a queryparam was undefinded it would be ignored, instead all the queryparams are appended.

So now I am hoping to append the query params to the queryparams argument, if the query param is used. I have no idea how to do this and have started my research.

default values are not acceptable as it would still produce a gross url. Thank you all very much

2 Answers2

0

This is quite tricky as there are lots of open issues for the same .

One such issue in git - https://github.com/angular/angular/issues/12347

Either you have to have optional routes like one for each type of query param eg

const routes: Routes = [
    { path: '', component: HomeComponent },
    { path: ':product', component: ProductComponent, resolve: { product: ProductResolver } },
    { path: ':product/:card', component: ProductComponent, resolve: { product: ProductResolver } },
    { path: ':product/:group/:card', component: ProductComponent, resolve: { product: ProductResolver } }];

Or you can take a look at this code i found in one of the gists on github . You can use in your router resolve. to get the params and check.

Link for the same - https://gist.github.com/e-oz/5a95f50336e68623f9e0

export class UrlParser
{
  getParameter(key) {
    return this.getParameters()[key];
  }

  getParameters() {
    // http://stackoverflow.com/a/2880929/680786
    var match,
      pl = /\+/g,  // Regex for replacing addition symbol with a space
      search = /([^&=]+)=?([^&]*)/g,
      decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
      query = window.location.search.substring(1);

    let urlParams = {};
    while (match = search.exec(query)) {
      urlParams[decode(match[1])] = decode(match[2]);
    }
    return urlParams;
  }

  setParameter(key:string, value) {
    let params = this.getParameters() || {};
    if (params[key]==value) {
      return true;
    }
    params[key] = value;
    let search = [];
    for (let k in params) {
      if (params.hasOwnProperty(k)) {
        search.push(encodeURIComponent(k)+"="+encodeURIComponent(params[k]));
      }
    }
    let query = '?'+search.join('&');
    let history = DOM.getHistory();
    if (history && history.replaceState) {
      history.replaceState(null, '', location.pathname+query);
    } else {
      return false;
    }
    return true;
  }
}

UPDATE

I think it has been handled in the new router as mentioned in one of tickets on GIT - https://github.com/angular/angular/issues/3525

Now the optional routes are seperated by localhost:3000/heroes;id=15;foo=foo ";".

The id value appears in the URL as (;id=15;foo=foo), not in the URL path. The path for the "Heroes" route doesn't have an :id token.

The optional route parameters are not separated by "?" and "&" as they would be in the URL query string. They are separated by semicolons ";" This is matrix URL notation — something you may not have seen before.

Take a look at this link might help - https://angular.io/guide/router#route-parameters-required-or-optional

Rahul Singh
  • 19,030
  • 11
  • 64
  • 86
  • your answer is impressive and I will look into matrix url notation. The answer below may be the one I am going with beause of its simplicity, and the need to hurry and get this product to market. Still you have taught me alot and I really appreciate it! –  Jul 12 '17 at 16:25
  • Angular actually has three kinds of parameters: required, optional (as you defined above) and query parameters. – DeborahK Jul 12 '17 at 17:24
  • Here is a link to more info: https://stackoverflow.com/questions/44864303/sending-data-with-route-navigate-in-angular-2/44865817#44865817 – DeborahK Jul 12 '17 at 17:50
0

I'm not sure if there's any easy way to conditionally add the parameters, other than manually going through each one individually. What would probably be easier is to build the whole object and then filter out and delete the ones that are missing.

onSubmit() {
    const queryParams = {
        guestCount: this.inputGuestNumber, countOption: this.inputCapacitySelected,
        cuisineSelected:this.inputCuisineSelected, privacySelected:this.inputPrivacySelected,
        venueTypeSelected: this.inputVenueTypeSelected, amenitiesSelected: this.inputAmenitiesSelected,
        neighborhoodSelected: this.inputNeighborhoodSelected
    }

    Object.keys(queryParams)
        .filter(key => queryParams[key] === null || queryParams[key] === undefined)
        .forEach(key => delete queryParams[key])

    this.router.navigate(['/venue-list', this.inputCity], {queryParams})
}
John Montgomery
  • 6,739
  • 9
  • 52
  • 68
  • that does seem alot easier. But why is the question I am asking myself. My understanding is not having the key : value pair. And having to inject those into the queryParam argument would be rough. Unless I am mistaken it would be alot of strings being coverted into code. Am I wrong? This is what I have so far in my research. –  Jul 12 '17 at 16:16