ember 2.17: calling a jquery document.ready() function - ember.js

I am really new to Ember, which I am asked to do and well, love to learn. Basically, the current project uses Gentelella Admin Dashboard. I being trying to get the dashboard to load properly but failed.
After I login, I get redirected to /dashboard/ route, which basically loads the main dashboard interface. Now the problem is I can't click-expand the menus on the sidebar nor toggle the sidebar menu. And the main page is not extended to fill the space, as in our current application.
I know the function init_start() takes care of the resize and the click, which is already added to vendor.js from custom.js but I can't seem to call the function from ember at all.
My latest attempt was using mixins but it failed too:
import Ember from 'ember';
export default Ember.Mixin.create({
activate: function() {
this._super();
init_sidebar();
}
});
then from dashboard.js route:
import HandleTempLoadMixin from '../mixins/handle-temp-load';
export default Route.extend(AuthenticatedRouteMixin,HandleTempLoadMixin, {
});
but still the function is not executed.
I have read that it is best to avoid working with jquery inside ember in SO but I have pretty much many JQuery functions that I cant transfer right now (nor sure why exactly since it says somewhere in the documentation jquery is built into ember itself).
Anyway, what is the best way to initailize the dashboard interface?

From my understanding you have some jQuery stuff that you would like to utilise. I suggest looking into Component's didInsertElement hook and triggering your custom code from there.
You can find more details in here https://guides.emberjs.com/v2.17.0/components/the-component-lifecycle/#toc_integrating-with-third-party-libraries-with-code-didinsertelement-code
In general, try avoid working with view related stuff in Routes. Ember's power comes from strong conventions. Learning where to place your code is crucial.

Related

Ember: Re-render a route's template when the model changes

I've noticed that a route doesn't re-render when the model changes (i.e. transitionTo the same route with a different model). I have some jQuery plugins set up on a particular page and I need them to re-render when the model changes, so it appears as a fresh page.
Is there a way to do this? Perhaps by observing the model's ID and firing a re-render of the route somehow?
Thanks in advance
I have an ember twiddle that, I believe, does what you're looking for, but first I would like to argue there are no straightforward ways to do what you're asking because it is the opposite of what an SPA is designed to do.
Data binding (without refreshing the view) is typically a boon of an SPA, and the SPA works hard to avoid brute force reloading/refreshing/rerendering the view at all costs. It took me a while to find a solution to your question as it is stated because it seems to go against Ember design principles. Even hooks like route refresh() are meant to update the model and bound data, not reload the template.
Although other people have asked the same question before, it seems that most answers guide users towards not refreshing the whole view. More often than not, the ideal of refreshing the view is an incorrect assumption.
Following previous examples, I would suggest that your goal shouldn't be to refresh the template completely, but rather, figure out how you can make your jQuery plugin better fit in to a Single Page App/client-side JS friendly design and have it reload as a natural part of the route lifecycle.
For instance, maybe the plugin can be reloaded/reset/re-run in afterModel() or somewhere similar.
That said, I was able to accomplish what you asked for using (in my opinion, a hack) Ember.run.later() so that I could invalidate an if block and force the content to rerender. Note, this is typically not what users want since (aside from design principle reasons) it causes UI flicker.
I have a component like so.
/* will-rerender.hbs */
{{#if show}}
{{yield}}
{{/if}}
And it has a JS file like so.
/* will-rerender.js */
import Ember from 'ember';
export default Ember.Component.extend({
show: false,
didReceiveAttrs() {
this._super(...arguments);
/*
Ugly hack, but we need to reset `show` in
a separate run loop in order to force the view
to rerender.
*/
this.set('show', false);
Ember.run.later(() => {
this.set('show', true);
});
}
});
You can invoke it like this...
/* your template */
{{#will-rerender cacheKey=model.id}}
... your content to rerender ...
{{/will-rerender}}
Whenever the model.id changes the component will invoke didReceiveAttrs() causing show to invalidate and the view to refresh.
As an aside, I think the behavior of switching between models would be much more natural with {{link-to}} rather than calling transitionTo yourself.

Ember 2 - Transition to route through component

I am trying to make a pagination component for ember 2 app.
Since it is a general purpose pagination component, I wanted to use it on many different routes. Because of that I need to somehow (in my mind) provide a name of my route for pagination links to work.
I can pass in my route name (string) to the component easily:
{{pagination-component myRoute='myCurrentRouteName'}}. And
inside of component: {{link-to myRoute (query-params page=1)}}
It works well for going to pages like: << First, < Previous, Next > , Last >>.
But I also wanted to have a select box with options pointing to all the pages, where if user selects a page, I can transition into that route with queryParams similar to this: myRoute?page=selectedPage.
All the tutorials for ember say that transitioning within the component is a no-no.
But how do I do it instead, given that I want my pagination to be generic and I don't want to have action within every single route that deals with pagination and provide same exact transitioning?
So far I found that I can inject the '-routing' into the component, which can work for transitioning within the component, but it also doesn't quiet work for some reason. Plus people say that it is private and unreliable.
I also tried making a Route Mixin with action so I can simply sendAction from the component with the selectedPage, but I don't know how to get the router (in order to call router.transitionTo) within my Mixin.
We should use public API for transitioning, that is provided in Route transitionTo and in Controller transitionToRoute. this is the recommended approach.
As you said, you can make it work in the component using Ember.getOwner(this).lookup('router:main').transitionTo('myRouteName') but that's strongly against good design.
You can define method named myTransitionToUrl inside actions hash of the Application route, and install ember-route-action-helper addon to call route action method myTransitionToUrl from component.
If you don't want to define method in application route, then you can define it in mixin and implement it in the required route. that's also will work.
My choice and Recommended approach would be, Say pagination-component has prev,next,transtionTo actions, then I will implement all those actions in Mixin and extend it in all route which uses pagination-component. and will inform any data changes to route through actions from component. that will ensure Data Down Actions Up strategy too.
If you are just transitioning to a different route, then the Latest possible way is,
If ember version is greater than 2.15, then you can inject RouterService and and call transitionTo method directly.
If you are using the ember version 2.15 or below, then you can use the router service polyfill to use RouterService.
import Ember from 'ember';
export default Ember.Component.extend({
router: Ember.inject.service(),
actions: {
next() {
this.get('router').transitionTo('other.route');
}
}
});

Component to be notified on route change in EmberJS 2

My task is to develop a menu component for an Ember 2 app. This is going to be a complex component whose visual representation changes as the user goes through routes. For instance it should disable particular menu and all its items when on "/index" route but enable it and some of its items when on "/details" and so on.
So, I've got a component that is passed a singleton model (stored in a Service currently, btw, is it a right place to store globally available singleton models in Ember?). It displays the stuff well but it does not respect the current route nor catches the route changes as user goes through the app. How can I achieve it?
Summing it up:
The component needs to get current route somehow to be able to display its initial state, for instance the user bookmarked the "/details" page and visited it.
The component has to deal with route changes somehow.
Is a Service a good place to hold a singleton model (which could potentially be fetched from server).
Can you provide your thoughts on how to tackle the three above?
SOLVED: Ok, here's how it is done, thanks to #Bek's suggestions:
import Ember from "ember";
export default Ember.Component.extend({
router: Ember.inject.service("-routing"),
didInsertElement: function() {
let r = this.get("router");
console.log("Initial route", r.get("currentRouteName"));
r.addObserver("currentRouteName", this, "currentRouteNameChanged");
},
"currentRouteNameChanged": function(router, propertyName) {
console.log(router.get("currentRouteName"));
}
});
MORE QUESTIONS :) - I had to surround the currentRouteNameChanged function name with quotes (to make it a string) otherwise it was not called. I assume I miss something very basic and obvious here?
One more issue is the funky service name -routing - #Bek, any hints on how could I figure it out myself, is there a list of injectable stuff I could look up information in? It is not yet in Ember documentation I assume but where in the source code of it to check it out? How stable -routing name in general, would it become *routing or something in final version?
Answer to 1 and 2:
In latest versions of ember 2.x (in 2.2 at least) router is available as service so you can inject it to component router: Ember.inject.service('-routing') and observe changes on currentRouteName, but it is currently private service so should be used with caution as it might change (might be renamed to routing), there is also rfc https://github.com/emberjs/rfcs/pull/38 which proposes routable components which will be part of ember in the future.
Anser to 3:
Services usually stateless, but there can be exceptions and services made to share global logic/objects so it is not a bad idea

Ember.js Overriding an add-on's component

I am fairly new to Ember.js and trying to use the datepicker component from ember-cli-jquery module (https://www.npmjs.com/package/ember-cli-jquery-ui) in my project.
The issue I'm facing is that I need to run some custom jquery initialization code after the datepicker component loads.
After research for several hours, came across this article http://mavilein.github.io/javascript/2013/08/01/Ember-JS-After-Render-Event/ and this stackoverflow post: Using Ember.js, how do I run some JS after a view is rendered?
The post describes using 'didInsertElement' hook to run any initialization code - however, as I'm using the ember-cli-jquery-ui plugin, I'm not sure how to do this without changing/modifying the code in node_modules/ember-cli-jquery-ui/addon/mixins/jqui-widget.js
I looked at the source code for ember-cli-jquery-ui and it turns out the above mentioned method is already being overridden. Reading through the API documentation on emberjs, it seems like any method can be extended and classses can be re-opened, I'm just not sure how to do it.
Is there a way I can further extend/override that method in my app.js or index.js for instance?
Any help would be greatly appreciated.
You can just extend the component and call the super method. and use this as the new component in you app
//app/components/my-date-picker.js {{my-date-picker}}
import DatePicker from "path/to/picker"
export default DatePicker.extend({
didInsertElement:function(){
//do things before super
this._super(); //this._super() instead of this.super()
//do things after super
}
})

Does ember require routes?

I'm writing a feed reader plugin for wordpress.
Feeds have entries. Click on a feed, show the entries from that feed.
I have that working in older versions of ember, but when I try to upgrade to the release candidates it seems like we have to have a router. Defining routes etc is turning into a major headache and I'm wondering if I can just use the databinding that I came to ember for.
Is there a way to just use the databinding to controllers and models without having to go through the whole router business?
Is there a way to just use the databinding to controllers and models without having to go through the whole router business?
Yes it's possible to use ember without the router. It will still be there in background but won't cause any trouble. Just set location: 'none' and then customize App.ApplicationController, App.ApplicationView and application.hbs as necessary. You may find it is still useful to customize the App.ApplicationRoute as well.
App.Router.reopen({
location: 'none'
});
FWIW #commadelimited is right, checkout the Peepcode video and consider taking advantage of the router.
Ember's routes have smart defaults so if you're app is pretty basic, you may not need to touch the routes.
location:none simply makes it so you're url doesn't show state changes, which can be useful
If you're app doesnt have any use for routes(maybe it's super small) you can simply put everything into a controller on your initial state/route and not worry about it.
But even if you have a simple setup of a few states:
App.Router.map(function() {
this.resource("index", { path: "/" }, function(){
this.route("stuff", { path: "/stuff" });
this.route("otherstuff", { path: "/otherstuff" });
});
});
the routes default action is take care of the magic behind that, so you shouldnt need to do anything :)