Click and load on same page


#1

Hi, How can I click on button and then display a box on same page?

for example, I have a DIV that it is hidden in a template by IF condition, as long as parameter == false. Then I would like to click a button on the page, update the value of parameter in the URL, then let the page read the query parameter and then if it is true, IF Condition will be true and therefore the DIV will be visible.

How can I achieve this using ember? what should be in router, controller and template ?

Thanks in advance.


#2

Your route should look something like this:

...
  queryParams: {
    parameter: {
      refreshModel: true, // if your model doesn't change, set this to false
    }
  },
...

Your controller should look like this:

...
  queryParams: ['parameter'],
  parameter: false,
...

The above will create the query param on the route and controller and “link” them to each other, more or less. See the guides for more info on that.

Then you should have an action on your button like so (obviously call it whatever you want):

<button {{action 'toggleDIV'}}>Click me</button>

Then in your controller:

...
  actions: {
    toggleDIV: function(){
      this.toggleProperty('parameter');
    },
  },
...

When you click the button, the action will be fired, toggling the property on the controller which changes the query param on the router, optionally reloading the model of the router. Then your div will be rendered (assuming your {{#if… }} is set up correctly of course).

If you wanted to load data outside of the router (not necessarily recommended) I would use the ember-concurrency addon.

EDIT: corrected the controller action above


#3

Hi dknutsen, Thanks, that worked. That was simplified version of what I kind a wanted to do. Now, I am wondering how I can achieve the same process but instead of a button, I have a table and clicking on a row in table, should cause the DIV to appear. I have onRowSelect(model) {} block in router, When I click on a row, it loads a new transitionTo to a new page, as different route. I would like to send the transition to current page with model ID, so I can display the DIV on same page without transition to a new page, and also get the model ID and display the data according to in the DIV.


#4

Helpful post of the month award


#5

In that case I’d probably recommend a nested route. As a rule of thumb anytime you have "nested’ views it’s a good candidate for nested routes. In this case you have a nice separation of concerns too. The “parent” route is concerned with fetching and rendering a list of items in a table (in the below examples I chose “users”). The “child” route is responsible for receiving and rendering the details of one of the items in the parent route.

Approach 1 - nested routes

Your table could be in your index route, and then you have a “detail” route.

Let’s say your table was for displaying users. You could put something like this in your router:

Router.map(function() {
  this.route('users', { path: '/users' }, function() { // the path param here is redundant, just wanted to be explicit
    this.route('user', { path: '/:id' });
  });
});

Then in your ‘users’ template and route you put everything pretty much just as you have it (just make sure you include an {{outlet}} in the template to render the child view into) but instead of doing a transitionTo('otherroute'); simply change it to transitionTo('users.user', model);and alternatively you could even use a link-to in the table instead of having the action and transitionTo (if it fits in your table of course).

Then in /templates/users/user.hbs you put the content of the DIV that you want to display (the details of the ‘user’ in this case). There are a lot of advantages to this approach, especially if you want to link directly to the URL <your app server>/#/users/4 for example, you will have fewer headaches with the data getting fetched, selected and displayed correctly.

Approach 2 - one route, query param instead of dynamic segment param

That said, you could continue the way you intended, where you just have one route and template, and when you select a table row it renders the details in the same template in the div. In that case you could add a second model to your route like so:

...
  queryParams: {
    parameter: {
      refreshModel: true,
    }
  },
  model: function(params){ 
    return Ember.RSVP.hash({
      users: this.store.findRecord("user", params.id)
      selectedUser: this.store.peekRecord("user", params.parameter)
    });
  },
...

Then in your template you could render the contents of model.selectedUser in our div. Since we set up ‘parameter’ to refresh the model every time you click a new table row the peekRecord will update to that new model. And since you can only select models from the table it means you’re guaranteed to have the record already (enabling you to user peekRecord). Of course you could also use findRecord, it would probably be redundant server work.

Your controller should already be set up correctly if you got the first example working, so then you’d be all set.