Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable parameter inheritance in ui-sref directive #376

Closed
tobigit opened this issue Sep 3, 2013 · 20 comments
Closed

Disable parameter inheritance in ui-sref directive #376

tobigit opened this issue Sep 3, 2013 · 20 comments
Labels
Milestone

Comments

@tobigit
Copy link

tobigit commented Sep 3, 2013

Is there a way to disable parameter inheritance in ui-sref directive?
I would like to have a second parameter, like this:

<a ui-sref="contacts.detail({ id: contact.id }, {inherit: false})">{{ contact.name }}</a>

With the second parameter i could set the options for the method $state.go().

@nateabele
Copy link
Contributor

Can you just pass null to the parameters you don't want?

@tobigit
Copy link
Author

tobigit commented Sep 4, 2013

Our Application has about 38 states. Every State has its own parameters. One state can have up to 12 parameters. When i pass null to every parameter of every state in every link (ui-sref), there would be very long ui-sref calls.

I would be happy if a optional second paramter of type boolean would disable inheritance like this:

<a ui-sref="contacts.detail({ id: contact.id }, false)">{{ contact.name }}</a>

@laurelnaiad
Copy link

If you define query parmeters (the things after the question mark) then would they be optional in ui-sref?

@tobigit
Copy link
Author

tobigit commented Sep 6, 2013

Example

My current URI: /contacts/teams&sortBy=Name&filterBy=test
My State: contacts.teams

Now I click on this link:

<a ui-sref="attachments.list({ type: 'private' })">list attachments</a>

Now my URI: /attachments/list&sortBy=Name&filterBy=test&type=private
My State: attachments.list

The query parameters sortBy and filterBy stay in URI until i overwrite it or until i switch to a state which has not defined these parameters in $stateProvider.

@laurelnaiad
Copy link

Nothing's simple, is it? :)

2 cents:

I'd hope that if parameters that are valid for a state are not specified and they are currently in scope when the ui-sref is invoked, that they retain their values -- and thus, if they are URL parameters, that they stay in the URL.

If they are not currently in scope, then they would result in being undefined; that they do not appear in the resulting URL; and that it is the application's responsibility to know what to do about undefined parameters.

@tobigit
Copy link
Author

tobigit commented Sep 6, 2013

Ok, when you have one controller and the states attachments.list and contacts.teams shares one scope, where the parameters values are stored, your explanation is comprehensible.
The issue is that the new state (example above: "attachments.list") has its own controller with an own scope with own default-values for parameters like sortBy and filterBy.
So our application throws an error because sorting by "name" (example above: &sortBy=name) is impossbile when column "name" doesnt exists in attachements list.

Inheritance of query parameters is great if parameters were inherited from parent to child state. But inheritance between "master-states" (example above: "contacts.", "attachments.") is confusing.

@laurelnaiad
Copy link

Inheritance of query parameters is great if parameters were inherited from parent to child state. But inheritance between "master-states" (example above: "contacts.", "attachments.") is confusing.

I think I agree. I wouldn't consider those to be the same parameters since there isn't an ancestral relationship -- thus they wouldn't be "in scope" when you go from one to the other -- the parameters just happen to have the same names.

@tobigit
Copy link
Author

tobigit commented Sep 10, 2013

So is there a chance for parameter implementation to disable url-parameter inheritance (between sibling states)?

@nateabele
Copy link
Contributor

@tobigit Could you maybe break down your state tree a little bit, so we can understand better how to craft a solution that's a little bit more optimal for you? I have an idea that I think is a little bit better and more extensible than just adding another parameter (to something that isn't a function anyway), but I want to make sure it'll work for you.

@tobigit
Copy link
Author

tobigit commented Sep 16, 2013

Sure, here is a snippet of our state configuration:

$stateProvider.state('users', {
    url: '/:workspaceId/users/?id&sortyBy&filterBy',
    controller: 'userController',
    templateUrl: '/views/users/index.html'
});

$stateProvider.state('teams', {
    url: '/:workspaceId/teams/?id&sortyBy&filterBy',
    controller: 'teamController',
    templateUrl: '/views/teams/index.html'  
});

My currently quick fix is to add some lines in angular-ui-router.js at line 1193.
So the click-handler for the link looks like this:

element.bind("click", function(e) {
        if ((e.which == 1) && !e.ctrlKey && !e.metaKey && !e.shiftKey) {

        // fixes parameter inheritance between sibling states
        var fromBase = $state.$current.name.split('.')[0];
        var toBase = ref.state.split('.')[0];

        var options = {};

        if (fromBase != toBase) {
            options['inherit'] = false;
        }
        $state.go(ref.state, params, options);
        // ***

        scope.$apply();
        e.preventDefault();
    }
});

@knalli
Copy link

knalli commented Sep 16, 2013

Okay, should we (@tobigit or me) send a solution as a PR?

I do not like the code above because the condition fromBase != toBase does not solve the original problem correctly. I would support inherit as an additional parameter for ui-sref, the open question is only interface aware: Should this be <a ui-sref="contact.detail({id: 1}, {inherit: false})"> (abstract) or <a ui-sref="contact.detail({id: 1}, false)"> (explicitly, precisely)?

Alternatively (or additionally), we could introduce a new "smart" behavior which recognize state changes and will not apply the current state params?

So, the code in question would be something like this:

      element.bind("click", function(e) {
        if ((e.which == 1) && !e.ctrlKey && !e.metaKey && !e.shiftKey) {
          var options = {};
          // Unless the state in question is a child state of the current one, the params will be not included.
          if (!$state.ref.contains($state.$current.name)) {
            options['inherit'] = false;
          }
          $state.go(ref.state, params, options);
          scope.$apply();
          e.preventDefault();
        }
      });

@tobigit
Copy link
Author

tobigit commented Dec 4, 2013

I added a pull request. Tests of the new regexp: https://www.debuggex.com/r/TuuflzAR_vZ2mWph/1

@timkindberg
Copy link
Contributor

I think we need both:

  • @tobigit's PR is a great feature, but not optimal for this particular issue, because adding the ability to specify options to sref, while cool, gives benefits beyond the scope of this issue by allowing modification of the other options (aka location, relative (probably not useful), notify, and reload (v0.3)). And of course you can also set inherit to false, but that could be useful in other ways, again beyond this issue.
  • @knalli's approach, however, is a good solution to this particular issue, showing how we could handle things in a smarter way for the user.

But I'm not sure @knalli's approach is actually everything we need, because you don't want to check for just if the to state is a child of the from state, I think inheritance is a bit more complicated than that.

So @nateabele I'm not entirely sure how inheritance currently works but I'm thinking it's supposed to work like this... say I have some states:

  • A - with param a
  • A.B - with param b
  • A.B.C - with param c
  • A.X - with param x
  • A.X.Y - with param y
  • A.X.Z - with param z
  • K - with param a
  • K.B - with param b

Assuming inheritance is true in all cases... if I go from:

  • A to A.B, then inherit a.
  • A.B to A.B.C then inherit a and b.
  • A.B.C to A.X then inherit a.
  • A.B.C to A.X.Y still only inherit a.
  • A.X.Y to A.X.Z then inherit a and x.
  • A to K then inherit nothing, even though they share same param name.
  • A.B to K.B, inherit neither a or b because they aren't the same param instance, even though name is the same.

God I know that's a lot to take in... hope you could understand it. So I'm in favor of @tobigit cleaning up his PR (squash and add tests). Then additionally implementing something that auto-inherits in the way I've laid out.

@jaydiablo
Copy link

I am facing this same issue, and built out a plunk before I found this issue, so figured I'd at least include it. It's a very simple case of what @tobigit described (I believe).

http://run.plnkr.co/hcaq99zIhV4CO30N/

There are two states, foo and bar, each are basically copies of each other but have different sort values. If you navigate to the Foo state (Foo link in the list at the top) then change the sort, you'll see the "sort" URL parameter change, but then if you click on the Bar link in the list at the top (without sort, second link) you'll be taken to the Bar controller, but the "sort" URL parameter will remain whichever "foo" sort you chose in the Foo controller.

Ideally, since the ui-sref is just set to "bar" in this case, and bar is not a child of foo in the state config, the sort shouldn't persist when that ui-sref is clicked.

Plunk's source: http://plnkr.co/edit/vZ7rucKQBs8d4oix0I5t

Perhaps useful for testing/describing the issue. :)

@timkindberg
Copy link
Contributor

@jaydiablo thank you for putting this together. This is a great working example of the issue.

@kevinsbennett
Copy link

I also am experiencing this issue. And I concur with timkindberg on how it should behave.

@nateabele
Copy link
Contributor

See ui-sref-opts, as implemented in #813.

@christopherthielen christopherthielen modified the milestones: 0.2.10, 1.5.0 Nov 16, 2014
@janhartigan
Copy link

For reference, the way to do this is:

ui-sref-opts="{inherit: false}"

@msieurtoph
Copy link

msieurtoph commented May 29, 2017

This did not work for me ...
I had to use ui-sref="myState({myParam:null})" to get real uninheritance ...

My State was this simple :

        .state('releases', {
            parent:'root',
            url:'releases/:releaseId',
            templateUrl: 'views/view-releases.html',
            data: ...
        })

releaseId is optional. If not supplied, the page will get the last releaseId from localStorage (and update URL)

When I was using version 0.4.2, I could use ui-sref="releases" to make it work ...
Since I migrated to version 1.0.3, it did not work anymore. I got the following error message when I come from sibling states :

Transition Rejection($id: 0 type: 6, message: The transition errored, detail: Error: Param values not valid for state 'releases')

I tried ui-sref-opts="{inherit: false}" with no luck.
I had to use ui-sref="releases({releaseId:null}) instead to get it working.

Any idea or explanation ?
Thx in advance.

@typhoon2099
Copy link

I seem to be hitting an issue somewhat similar, but my issue is that params between the same route are being stored. I have a search page which accepts params, and some links to provide access to some predefined searches. The problem I have is that setting ui-sref-opts="{inherit: false}" prevents the query params from being copied between these links, but the link also contains an id for a record in my database, which mean the link isn't valid, and I have to add a lot of code in the controller to inject the id into the list of params for each link (which comes from my database, so I have to intercept and modify the values in the array.

Is there a way to disable just the query params and leave the URL params alone? Or at least specify which params to ignore between states/links?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests