currently I'm thinking of the way to load statics into my Ember app.
The problem:
I have app branded logo, app name, app title (browser tab label), texts for routes etc.
What I'm doing now is the following:
model() {
let defaultHeaderModel = {
logo: '/img/logo-cloud.svg',
brand: {
name: 'CloudCenter',
logo: '/img/logo-cloud.svg'
},
userLinks: [{
text: 'Logout',
route: 'logout'
}],
navigation: [{
text: 'Login',
route: 'login'
}]
};
}
As you can see all of the values are hardcoded. What I'd like to do is to somehow load that "statics" and use them through some variables. For ex: header.logo = resources.logo.
My thoughts:
1) Use environment - store all of that values in the config.js and import it where needed. Cons: not sure if that data belongs to environment
2) ES6 POJO which can be imported to the app.
3) .json and some staticsService which will load .json file and through it I will have access to that values.
Are there any standardized approach to do such things? Or maybe better suggestions?
You can create service, and have method(loadData) which will return Promise and will be resolved with your JSON data and update property in service. You need to call loadData in beforeModel hook, after the all the promises resolved only then it will move to model hook.
Refer twiddle basic demonstration
services/my-service.js
import Ember from 'ember';
export default Ember.Service.extend({
defaultHeaderModel:{},
loadData(){
var myServiceDataLoadPromise = Ember.RSVP.Promise.resolve({one:1});
myServiceDataLoadPromise.then(result =>{
this.set('defaultHeaderModel',result);
});
return myServiceDataLoadPromise;
}
});
routes/application.js
inside beforeModel hook, you can load service with data, it can be done any of the route which requires data.
import Ember from 'ember';
export default Ember.Route.extend({
myService: Ember.inject.service(),
beforeModel()
{
return Ember.RSVP.all([this.get('myService').loadData()]);
}
});
controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
myService: Ember.inject.service(),
appName: 'Ember Twiddle'
});
templates/application.hbs
{{myService.defaultHeaderModel.one}}
Related
I wrote a service for loading notifications:
import Ember from 'ember';
export default Ember.Service.extend({
sessionUser: Ember.inject.service(),
store: Ember.inject.service(),
read() {
let currentUserId = this.get('sessionUser.user.id');
return this.get('store').query('notification', {
userId: currentUserId,
read: true
});
},
unread() {
let currentUserId = this.get('sessionUser.user.id');
return this.get('store').query('notification', {
userId: currentUserId,
read: false
});
}
});
I want to change the colour of an icon in the navigation bar when there are unread notifications. The navigation bar is a component:
import Ember from 'ember';
export default Ember.Component.extend({
notifications: Ember.inject.service(),
session: Ember.inject.service(),
hasUnreadNotifications: Ember.computed('notifications', function() {
return this.get('notifications').unread().then((unread) => {
return unread.get('length') > 0;
});
})
});
And the template then uses the hasUnreadNotifications property to decide if the highlight class should be used:
<span class="icon">
<i class="fa fa-bell {{if hasUnreadNotifications 'has-notifications'}}"></i>
</span>
However, it doesn't work. Although the store is called and notifications are returned, the hadUnreadNotifications doesn't resolve to a boolean. I think this is because it returns a promise and the template can't deal with that, but I'm not sure.
Questions
Is it idiosyncratic ember to wrap the store in a service like this. I'm doing this because it feels clumsy to load the notifications in the application route just to show the count.
Why doesn't hasUnreadNotifications return a boolean?
Is it possible to make read and unread properties instead of functions, so a computed property can be created in the service to calculate the count?
Returning promise from computed property will not work. Computed properties are not Promise aware. to make it work you need to return DS.PrmoiseObject or DS.PromiseArray.
You can read other options available from this igniter article.
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Component.extend({
notifications: Ember.inject.service(),
session: Ember.inject.service(),
hasUnreadNotifications: Ember.computed('notifications', function() {
return DS.PromiseObject.create({
promise: this.get('notifications').unread().then((unread) => {
return unread.get('length') > 0;
})
});
})
});
My web app is built using Ember.JS and Firebase for storing data. It also serves as a backend for a mobile app. Users can use mobile app to send a 'help-request' - the app manipulates directly with the Firebase records. When the change is made admin of the web app can see the notification on the screen. That works fine. Now I want to add a sound to this notification.
My general idea to solve it to add an observer that will be triggered when a new record of help-request type is added to the database.
I found a post sort of explaining how to do it but it's using deprecated methods like ArrayControler.
I added a simple observer to help-request model that is triggered when property/ies of the record are modified. That works fine but seems to be a hack rather than a real solution.
So the big question is:
1. Is there any callback, or event, or notification that I can subscribe to check if a new record is created in the Firebase? If so how would I subscribe to it?
import DS from 'ember-data';
export default DS.Model.extend({
device: DS.attr('string'),
userName: DS.attr('string'),
locationName: DS.attr('string'),
type: DS.attr('string'),
fullNameChanged: function() {
// deal with the change
console.log("FULL NAME");
}.observes('device').on('init')
});
My Second approach:
Did Create - never called when the changes are made to Firebase directly.
didCreate:function(){
console.log("Created");
var mySound = soundManager.createSound({
url: 'assets/beep22.mp3'
});
mySound.play();
},
Did update - called but the property is not persisted
didUpdate:function(){
console.log("Updated");
console.log((this.get('shouldPlay')));
}
Did Load - seemed to be the best approach but the changes are not persisted :(
didLoad:function(){
console.log("Did load");
if(this.get('shouldPlay')){
var mySound = soundManager.createSound({
url: 'assets/beep22.mp3'
});
mySound.play();
this.set('shouldPlay','false');
this.save().then(() => {
console.log("saved");
},(error)=>{
console.log(error);
});
}
}
Update:
this.set('shouldPlay','false');
should be
this.set('shouldPlay',false);
This is how it finally worked.
When firebase adds new record into the store it's actually loaded not created. So you can use didLoad hook on ember model.
I would also suggest creating service to play sounds. It will make things easier down the road.
// models/help-request.js
import DS from 'ember-data';
import Ember from 'ember';
const {inject: {service}} = Ember;
export default DS.Model.extend({
soundPlayer: service(),
didLoad() {
this._super(...arguments);
this.get('soundPlayer').newHelpRequest(this);
},
});
// services/sound-player.js
import Ember from 'ember';
export default Ember.Service.extend({
init() {
this._super(...arguments);
const beep = soundManager.createSound({
url: 'assets/beep22.mp3',
});
this.set('beep', beep);
}
play(sound) {
this.get(sound).play();
},
newHelpRequest(helpRequest) {
if (!helpRequest.get('_didNotify')) {
helpRequest.set('_didNotify', true);
this.play('beep');
}
},
});
I have a project where I need to build an Ember application. The application will have many routes and some of the routes will have some model.
My problem at the moment is that some information is global, meaning they are present in each page (.hbs) and I need to update it periodically.
I've tried to put information on the application route like the following but it didn't work, the content is not accessible on other routes:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON('/api/users/current')
}
});
I've also tried to reload the information with a setInterval but this didn't work either.
import Ember from 'ember';
export default Ember.Route.extend({
init: function() {
var thyself = this;
var interval = setInterval(function(){
thyself.my_reload()
}, 1000);
this.set('interval', interval);
this.set('counter', {});
},
my_reload: function() {
var counter = this.get('counter');
if (counter >= 10) {
clearInterval(this.get('interval'));
}
this.set('data', Ember.$.getJSON('/api/users/current'));
}
});
Where can I place this information so it will be available on all routes? And how can I reload the information periodically?
I'm using ember-cli
#NicosKaralis,
you should use service for it.
You can generate it by command: ember generate service name-of-service
And there you should create methods.
When you want to get access from your controller you should inject it in your controller:
nameOfService: Ember.inject.service(), (remember camelCase here)
and if you want some method from your service in your controller you will use it like this (example with computed property, you can also use it without computed property):
someComputedFunctionInController: Ember.computed(function() {
this.get('nameOfService').yourFunctionFromService();
},
nextComputedFunctionInController: Ember.computed(function() {
this.get('nameOfService.getSomethingFromService');
}
for more:
https://guides.emberjs.com/v2.7.0/tutorial/service/
Hope, it will help you.
I've done
ember g route auth
ember g route auth/pending
Which then gave me :
app/
routes/
auth/
pending.js
auth.js
and my router has
this.route('auth', function() {
this.route('pending', { path: '/pending/:steamid/:token'});
});
Which everything is fine, when I visit
http://localhost:4200/auth/pending/1/2
The page loads, but how do I access :steamid and :token outside of the model.
I'd like to use it so that I can set values in my session service
Like:
import Ember from 'ember';
export default Ember.Route.extend({
session: Ember.inject.service(),
steamID: this.get(// Params Some How),
token: this.get(// Params some How)
thing(params) {
this.get('session').set('tokenID', token),
this.get('session').set('steamID', steamID)
}
});
^^ Pseudo code to express what I'm trying to accomplish.
While it's not in the website documentation, looking at the source code of the Transition object passed to some Route hooks (e.g. afterModel and beforeModel) it have a params property which contains the dynamic segment params.
So you can, for example:
import Ember from 'ember';
export default Ember.Route.extend({
session: Ember.inject.service(),
thing(params) {
// Do some check and returns the result
},
beforeModel (transition) {
if (!this.thing(transition.params)) {
transition.abort();
this.transitionTo('/login');
}
}
});
You can set them in your service from many different hooks:
import Ember from 'ember';
export default Ember.Route.extend({
session: Ember.inject.service(),
/* Access from beforeModel */
beforeModel(transition) {
this.get('session').setProperties({
tokenID: transition.params.token,
steamID: transition.params.steamid
});
},
/* Access from model */
model(params, transition) {
this.get('session').setProperties({
tokenID: params.token,
steamID: params.steamid
});
}
});
If you ask me model hook is the best choice. Especially if you want your query params to refresh the model every time they change (see guide).
Pretty new to Ember so maybe someone can help me out. I keep running across this error and have no idea how to solve it.
Ember : 2.5.1
Ember Data : 2.5.3
Below is my router.js.
//app/router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.route('organization', {path: '/organization/:id'}, function(){
this.route('about', { path: '/about' });
this.route('admin', { path: '/admin' }, function(){
this.route('team', { path: '/team/:team_id' });
});
});
});
The organization/:id/about and organization/:id/admin routes work fine. But when I try to load the organization/:id/admin/team/:team_id route, the error is thrown. Below is the routes/organization/admin/team.js file:
//app/routes/organization/admin/team.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
let organization = this.modelFor('organization');
return organization.get('team');
}
});
Not really sure what other information I should post, so please ask for any additional information you may think is necessary to help debug. My guess is it's something pretty simple and I'm completely oblivious to it.
EDIT
I've added a couple more files to help diagnose the problem:
//app/routes/organization.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.store.findRecord('organization', params.organization_id)
}
});
//app/routes/organization/admin.js
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
changeValue(){
this.currentModel.save();
}
}
});
Where currentModel is the model for the organization route. I've removed the organization.admin.team model hook for now and am just testing a
{{#link-to 'organization.admin.team' model.team.id}} Team {{/link-to}}
in a component rendered in the organization.admin template where I pass model=model. But now I get the same error (Assertion Failed: You need to pass a model name to the store's modelFor method) in the Javascript console when rendering the organization.admin template.
If you pass Object to {{#link-to}} helper. It skips the model hook. So you could basically send {{#link-to 'team' organization.team}}Without having to write "model" hook.
"It makes sense and it might save a request to the server but it is, admittedly, not intuitive. An ingenious way around that is to pass in, not the object itself, but its id" - https://www.toptal.com/emberjs/the-8-most-common-ember-js-developer-mistakes".
So you should do
hbs
{{#link-to 'team' organization.team.id}} Link to team management {{/link-to}}
route
model(params) {
return this.store.findRecord('team', params.team_id)
}
you can use modelFor('parent') method to get organization model.
like that
//app/routes/organization/admin/team.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
let organization = this.modelFor('parent');
return this.store.findRecord('team', params.team_id)
}
});
i think you wants to do something like that.
basically ember does not support nested routes.