Focusing on element using Ember Components - ember.js

I have an element which's height expands upon hover, however the page does not scroll down when the element extends beyond the view box.
I've heard using jquery to focus on the element upon mouseEnter allows this to work properly.
Here's what I have so far:
export default Ember.Component.extend({
mouseEnter() {
$(this).focus();
}
});
I've just started using Ember and am not 100% on how components work, so any information is welcome.

You were almost there.
export default Ember.Component.extend({
mouseEnter() {
this.$().focus();
}
});

Related

Differences beetween ModalController and NavController

I need to understand the differences between ModalController and NavController in Ionic 2. When should I choose NavController and when to choose ModalController?
In the ModalController doc:
A modal uses the NavController to present itself in the root nav
stack. It is added to the stack similar to how NavController.push
works.
So we can say, in mechanism, they are the same. Lets talk about UX.
A Modal is a content pane that goes over the user's current page
A modal actually go over the page. It is like a popup. In small device, it take all the space of screen so you can not realize the diffentce from it and page. But if you test it in tablet like a ipad you will see the modal just take a part of screen and the current page is behind it.(Image description below).
What should be used?
In most case, you can use modal or page base on what you prefer but to ensure the properly UX modal should be used in case editing, making choice or getting information, other case page should be used
The ModalController is used to create and present modals. Modals are commonly used for galleries, edit forms, and other content that should be push on top of the current page.
import { ModalController } from 'ionic-angular';
import { Page1 } from './pages';
constructor(private modalCtrl: ModalController) {}
let modal = this.modalCtrl.create(Page1);
modal.present();
modal.onDidDismiss(() => {
// Action done after dismissing the modal.
});
The NavController is used for navigation functionality (think about Tabs or just basic page navigation). This controller also contains your navigation history.
import { NavController } from 'ionic-angular';
import { Page1 } from './pages';
constructor(private navCtrl: NavController) {
}
this.navCtrl.push(Page1);
So there are two different approaches to present the desired page. For more information/options/methods please ready the provided links, containing all available features available on the Modal- and NavController components.

How do I display a busy cursor during a route transition in Ember?

What is the best technique to generically change to a busy cursor during transition to a new route in Ember.js (1.13.10)? With data retrieval, this may take a couple of seconds.
The answer here indicates a method to do this with saving data:
Changing mouse cursor while Ember content is saving
...and indicates this is very straight forward with route transitions, but I can't seem to find an example or anything in the documentation.
Thanks in advance for any help on this.
We can use loading hook of Route.
app/routes/application.js:
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
loading(transition, route) {
$('body').css({ cursor : 'wait' });
this.router.one('didTransition', () => {
$('body').css({ cursor: 'default' });
});
return true; // Bubble the loading event
}
}
});
Working demo. (output is sandboxed so make sure your mouse is over body in output window)
Full code behind demo.
I've used $('body') as element to style cursor. You can probably use more global approach.

Default computed properties with Ember 2.0

With Ember 2.0, there is a deprecation for modifying properties in a component's didInsertElement hook. The following scenario exposes a problem when trying to integrate other third party libraries, in this case d3.
I have an ember component that wraps a d3 visualization, having as tagName: svg. There are two properties which are passed down from the parent into this component, the width and height. There are observers on these two properties within the d3 component to update the visualization to make it responsive to changes in the window size.
The problem arises in the parent component. I am currently binding to the window resize event, running Ember.run and a callback which sets the windowSize property in the component. I have two computed properties which depend on windowSize, the width and height which are computed according to the DOM's width and height (which are dynamic thanks to columns in bootstrap). Hence, the computed properties look like:
halfWidth: Ember.computed('windowSize', function() {
return $(this.get('halfSelector')).first().width();
})
However, when passing the computed property to the d3 component as {{d3-component width=halfWidth}} there is no default. This computed property is only computed when the resize event on the window is fired. If I resize the window the d3 component updates correctly with the new width.
didInsertElement() {
$(window).on('resize', () => {
Ember.run(() => {
this.set('windowSize', $(window).width());
});
});
// In order have the computed properties to have defaults, one could do
// $(window).trigger('resize')
// However this line is responsible for raising the deprecation notice.
}
How do I give the computed property a default value which depends on a width of a DOM node after the component has been inserted into the DOM?
In order to get rid of the deprecation, I changed the definition of the didInsertElement to the following:
didInsertElement() {
let onWindowResize = () => {
this.set('windowSize', $(window).width());
};
$(window).on('resize', () => { Ember.run(onWindowResize); });
Ember.run.scheduleOnce('afterRender', onWindowResize);
}
I got inspiration from https://github.com/emberjs/ember.js/issues/11493. The problem was also referenced as Forcing layout calculations to use in further positioning. In order to avoid the deprecation of setting properties in the didInsertElement hook, one uses the afterRender queue to schedule the change.

Extendible helper views in ember

So, I was hoping to be able to create a helper (master) view for my application, the main reason is that I want to implement a resize function.
Example.
App.View = Ember.View.extend({
init: function() {
$(window).resize(this.resize.bind(this));
this._super();
}
});
And then extend it
App.AmazingView = App.View.extend({
resizing: false,
resize: function() {
this.set('resize', true);
}
});
So, that's an example of what I wanted to achieve, but unfortunately it causes some problems.
If I go to the route that is using the Amazing view then everything works fine, it's only until you navigate around the application after and then return to that same route I face the following error.
Uncaught Error: Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.
I'm pretty sure this is happening because I'm extending that view, any ideas on why this happens or what I should actually be doing?
When you do $(window).resize(this.resize.bind(this)); you are attaching an event not managed for ember. When you leave the view, transitioning to other route, ember will cleanup event listeners and destroy the view. Now your view is in a "dead" state. But the resize handler is still present and when it triggers, a change is performed in a dead view. I think that it is causing your problem.
You can use the didInsertElement and willClearRender to bind and unbind your event.
App.View = Ember.View.extend({
_resizeHandler: null,
didInsertElement: function() {
this._super();
// we save the binded resize function to keep the identity, so unbind will remove
this._resizeHandler = this.resize.bind(this);
$(window).bind('resize', this._resizeHandler);
},
willClearRender: function() {
this._super();
$(window).unbind('resize', this._resizeHandler);
}
});
This sound like a feature that would fit perfectly into an ember mixin. This solution would offer more flexibility, then you could extend other views and also provide the resize features...
http://emberjs.com/api/classes/Ember.Mixin.html

Ember.js routing, outlets and animation

It seems like if you want to animate a transition between states using the new Ember.js router and outlets, you're out of luck, since the previous content of an outlet will be destroyed before you have a chance to animate it. In cases where you can completely animate one view out before transitioning to the new state, there's no problem. It's only the case where both old and new views need to be visible that's problematic.
It looks like some of the functionality needed to animate both the previous outlet content and the new was added in this commit, but I'm not sure I understand how to use it.
There's also been some discussion about using extra transitional routes/states to explicitly model the "in-between" states that animations can represent (here and here), but I'm not sure if it's currently possible to match this approach up with outletted controllers and views.
This is similar to How *not* to destroy View when exiting a route in Ember.js, but I'm not sure overriding the outlet helper is a good solution.
Any ideas?
I am currently overriding didInsertElement and willDestroyElement in some of my view classes to support animations. didInsertElement immediately hides the element and then animates it into view. willDestroyElement clones the element and animates it out of view.
didInsertElement: function ()
{
this.$().slideUp(0);
this.$().slideDown(250, "easeInOutQuad");
},
willDestroyElement: function ()
{
var clone = this.$().clone();
this.$().replaceWith(clone);
clone.slideUp(250, "easeInOutQuad");
}
Personally, I don't want to start wrapping my outlets in superfluous ContainerViews just to support animations.
You should check this out: https://github.com/billysbilling/ember-animated-outlet.
Then you can do this in your Handlebars templates:
{{animatedOutlet name="main"}}
And transition from within a route like this:
App.ApplicationRoute = Ember.Route.extend({
showInvoice: function(invoice) {
this.transitionToAnimated('invoices.show', {main: 'slideLeft'}, invoice);
}
});