how to remember ember-i18n language choice on browser refresh - ember.js

I tried first something like this in my application controller:
init123: function() {
var locale;
if (this.session.get('lang') === null || this.session.get('lang') === undefined)
locale = ENV.i18n.defaultLocale;
else
locale = this.session.get('lang');
this.get('i18n').set('locale', locale);
}.on('init'),
but this only works when the user is logged in. If not, always the default is set.
Then I tried stuff with the initalizer like on this answer.
How to set the i18n.locale from within an initializer from Artych
But how do I remember the last choice done in the browser?
Thx

You need to persist the preference somewhere. Take a look at the ember-localforage-adapter or ember-local-storage packages.

If you are using ember-simple-auth you can save it into the session.

Related

Ember active link

I have a route where I want to make a sibling route's link-to's active as well. I have tried using current-when in the link-to, but it's not working for me.
my routes are as follows
//projects
//projects/:project_id
//projects/:project_id/user/:user_id
When I navigate to //projects/:project_id route, the right link is set to active. I want the same link to be active on the //projects/:project_id/users/:user_id route.
My link-to in the parent //projects hbs template is
{{#link-to "projects.project" item.projectID current-when="projects.user" tagName="tr"}}
What am I doing wrong here?
UPDATE
I was able to get it to initially work when the route is rendered by using an edited version of #ykaragol's helper function and link-to...
{{#link-to "projects.project" item.projectName active=(calculate-active 'projects.user projects.project' item.projectName) tagName="tr"}}
compute(params, hash){
var pathname = window.location.pathname.split('/');
var pathProj = pathname[2];
var currRoute = this.get('currentRouteName');
var routes = params[0].split(' ');
if( ($.inArray( currRoute, routes) > -1) && (pathProj == params[1]) ){
return true;
}
return false;
}
But it's not updating when I click on a different project...
If routes don't have dynamic segments, it works as described in docs. I've tested it within this twiddle.
But I couldn't make it work while using dynamic segment. Please check this twiddle. I suspect this maybe a bug. You can ask this question in slack.
By the way, as a workaround, you can pass a boolean to the currentWhen property (as mentioned in docs). So you can write a helper or a computed property to calculate it with a regex.
Updated:
As a second workaround, you can handle active property of link-to by yourself. Try this twiddle.

Allow binding to any data-* attribute on an ember component

I am designing a library whereby I would like to allow the user to supply any data attributes they might like.
{{my-component data-type='hello' data-name='world'}}
I don't know ahead of time which data attributes they might like to bind to so can't add them to the attributeBindings array.
Is there a workaround for this?
Use the didReceiveAtts hook of your component:
didReceiveAttrs(params){
let newAttrs = params.newAttrs;
let attributeBindings = Ember.A();
Object.keys(newAttrs).forEach((attr)=>{
if(attr.indexOf('data-')>= 0){
attributeBindings.pushObject(attr);
}
});
this.set('attributeBindings', attributeBindings);
}
Look that Sample twiddle
Updated, after deprecation:
Since arguments of didReceiveAttrs function are deprecated, you need to change the code as the following:
didReceiveAttrs(){
let attributeBindings = Ember.A();
Object.keys(this).forEach((attr)=>{
if(attr.indexOf('data-')>= 0){
attributeBindings.pushObject(attr);
}
});
this.set('attributeBindings', attributeBindings);
}
See updated twiddle.
I guess after v3.10 you can do this without any hacks with the angle bracket invocation (and if required pass further using the ...attributes). So in my simplest case it was as simple as
<MyComponent data-aaa="bbb"/>

Ember makes unwanted call to backend in model hook

I want to be able to retrieve a certain conversation when its id is entered in the URL. If the conversation does not exist, I want to display an alert message with a record not found.
here is my model hook :
model: function(params){
return this.store.filter('conversation', { status : params.status}, function(rec){
if(params.status == 'all'){
return ((rec.get('status') === 'opened' || rec.get('status') === 'closed'));
}
else{
return (rec.get('status') === params.status); <--- Problem is here
}
});
}
For example, if I want to access a certain conversation directly, I could do :
dev.rails.local:3000/conversations/email.l#email.com#/convid
The problem is when I enter a conversation id which doesn't exist (like asdfasdf), ember makes call to an inexisting backend route.
It makes a call to GET conversation/asdfasdf. I'm about sure that it is only due to the record not existing. I have nested resources in my router so I'm also about sure that it tries to retrieve the conversation with a non existing id.
Basically, I want to verify the existence of the conversation before returning something from my hook. Keep in mind that my model hook is pretty much set and won't change, except for adding a validation on the existence of the conversation with the id in the url. The reason behind this is that the project is almost complete and everything is based on this hook.
Here is my router (some people are going to tell me you can't use nested resources, but I'm doing it and it is gonna stay like that so I have to work with it because I'm working on a project and I have to integrate ember in this section only and I have to use this setup) :
App.Router.map(function(){
// Routing list to raw namespace path
this.resource('conversations', { path : '/' }, function() {
this.resource('conversation', { path : '/:conversation_id'});
});
});
This also happens when I dont specify any id and I use the hashtag in my url like this :
dev.rails.local:3000/conversations/email.l#email.com#/ would make a call to conversation/
I know it is because of my nested resource. How can I do it?
By passing a query to filter (your { status : params.status}) you are asking Ember Data to do a server query. Try removing it.
From the docs at http://emberjs.com/api/data/classes/DS.Store.html#method_filter:
Optionally you can pass a query, which is the equivalent of calling find with that same query, to fetch additional records from the server. The results returned by the server could then appear in the filter if they match the filter function.
So, remove the query:
model: function(params){
return this.store.filter('conversation', function(rec) {
if (params.status == 'all') {
return rec.get('status') === 'opened' || rec.get('status') === 'closed';
} else {
return rec.get('status') === params.status;
}
});
}
Ok so here is what I did. I removed my nested resource because I realised I wasn't using it for any good reason other than redirecting my url. I decided to manually redirect my url using javascript window.location.
This removed the unwanted call (which was caused by the nested resource).
Thanks to torazaburo, you opened my eyes on many things.

Is it possible to change the filename convention in the Ember CLI?

My team decided that we wanted to be consistent with our filename naming conventions and decided that we want to stick with underscores across all of our projects; this is not just Ember/frontend projects, but APIs, DBs, pattern library, style guides, etc. We also want to use the Ember CLI for or next frontend project. Is there an option to change the "dasherized" naming convention to be "underscored?" If not, how would we go about solving this? I'm hoping the solution would be easier than just making our own fork of the CLI.
Based on runspired's suggestion, here's a custom resolver that converts modules with _ to -:
import Resolver from 'ember-resolver';
import ModuleRegistry from 'ember-resolver/utils/module-registry';
function DasherizedModuleRegistry(entries) {
var keys, key;
this._entries = entries || requirejs.entries;
// Convert underscore in module names to dashes
keys = Object.keys(this._entries);
keys.forEach((key) => {
var dasherizedKey = key.replace(/_/g, '-');
if (dasherizedKey !== key) {
this._entries[dasherizedKey] = this._entries[key];
delete this._entries[key];
}
});
}
DasherizedModuleRegistry.prototype = Object.create(ModuleRegistry.prototype);
DasherizedModuleRegistry.prototype.constructor = DasherizedModuleRegistry;
export default Resolver.extend({
init: function() {
this._super();
if (!this._moduleRegistry || !(this._moduleRegistry instanceof DasherizedModuleRegistry)) {
this._moduleRegistry = new DasherizedModuleRegistry();
}
},
});
Place this into app/resolver.js in your ember-cli app. We have a mix of components/foo_bar.js and components/bar-foo.js and this resolver works for us.
Note that this conversion will be run in the client's browser on application boot and might slow it down with a large codebase.

Format a property before displaying it

Hello StackOverflow experts,
I would like to know if it would be possible to use Ember.js' computed properties to modify the value of the property before returning to whatever object requests it.
Imagine this simple example:
I have a User object with mail property
When I set the property, I want the email address to change from first.last#example.com to first.last#anotherexample.com, then return it
When I request the property ( via User.get ) I want to get the modified property back.
I think it should be pretty simple by utilising another 'helper' property, like formatted_mail, where I would store and retrieve the formatted value, but I wonder if something like this can be done without additional model properties.
So far, I have this coffescript code, but I always get 'undefined' when reading the property, even though I set it before, so I suspect the value does not get saved by Ember anywhere:
mail: ( ( key, value ) ->
if arguments.length == 1
return this.get 'mail'
else
return value.split( '#' )[0] + '#anotherexample.com'
).property 'mail'
Thank you for your assistance!
You are close to solution.
As computed properties are always cached by default in Ember (you could disable this behaviour using .volatile()), you do not have to specify what to do when arguments.length is 1, except if you want to specify a default value.
So here it should looks like:
App.User = Ember.Object.extend({
mail: function(key, value) {
if (arguments.length === 2) {
return value.split('#')[0] + "#tieto.com";
}
return null;
}.property()
});
The return null just specify the default value.
When you set the mail property, it will cache the returned value and always returns it without recomputing this property.
Note that you can do that only because the mail property does not depend on other properties. If you were declaring it with .property('anotherProperty'), the mail property will be recomputed any time anoterProperty changes. So in the example above it will reset it to null.
You can try it in this JSFiddle.