Any easy way to test Ember loading substates? - ember.js

Is there a easy way in the route so I can test loading substates in Ember 2
I have tried this but it doesn't work. In the originating route, I have:
actions: {
willTransition(transition) {
this.sleep(5000);
}
},
sleep(time) {
return new RSVP.Promise((resolve) => setTimeout(resolve, time));
}

To see loading substate,
model() {
return new RSVP.Promise((resolve, reject) => {
Ember.run.later(() => {
resolve("failed to load application model");
}, 500);
});
}
To see error loading substate,
model() {
return new RSVP.Promise((resolve, reject) => {
Ember.run.later(() => {
reject(
new Error('failed to load application model')
);
}, 500);
});
}
You should have corresponding hbs file to show. refer ember official guide. https://guides.emberjs.com/v2.8.0/routing/loading-and-error-substates/

Related

Is it possible to live reload react-intl messages during development

Is it possible to live reload react-intl messages during development(for default language)?
I mean like Hot Module Loading, only updated message should be affected. Any ohter solution without running extra script or refreshing whole page will work too.
Thank you.
In case anybody need it, I wrote HOC for this;
import React, {Component} from "react";
import {IntlProvider} from "react-intl";
const url = location.protocol + '//' + location.host + "/";
class IntlLoader extends Component {
constructor(props) {
super(props);
const {initialLocale: locale, initialMessages: messages} = props;
this.state = {locale: 'en', messages};
}
fetchLanguagesForDevelopment = () => {
// if development, use hot loading
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
this.setState({...this.state, loading: true})
fetch(url + "reactIntlMessages.json")
.then((res) => {
return res.json();
})
.then((messages) => {
this.setState({loading: false})
if (messages !== this.state.messages)
this.setState({...this.state, messages})
})
.catch((error) => {
this.setState({error, loading: false})
})
} else {
const messages = require('../../dist/reactIntlMessages.json')
if (this.state.messages !== messages)
this.setState({...this.state, messages, loading: false})
}
}
componentDidMount() {
this.fetchLanguagesForDevelopment()
}
componentWillReceiveProps(nextProps) {
this.fetchLanguagesForDevelopment()
}
render() {
const {error, messages, loading} = this.state;
//if (loading) return (<div>Please wait...</div>)
if (error) return (<div>Error While Loading Language</div>)
return (
<IntlProvider {...this.state}>
{this.props.children}
</IntlProvider>
);
}
}
export default IntlLoader
You can module.hot.accept your translated messages and render it as argument. See this example in react-boilerplate
https://github.com/react-boilerplate/react-boilerplate/blob/v3.5.0/app/app.js
const render = (messages) => {
ReactDOM.render(
<Provider store={store}>
<LanguageProvider messages={messages}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</LanguageProvider>
</Provider>,
MOUNT_NODE
);
};
if (module.hot) {
// Hot reloadable React components and translation json files
// modules.hot.accept does not accept dynamic dependencies,
// have to be constants at compile-time
module.hot.accept(['./i18n', 'containers/App'], () => {
ReactDOM.unmountComponentAtNode(MOUNT_NODE);
render(translationMessages);
});
}

Delay in retrieving data from Ionic 2 storage

Before I launches the app I will check with local storage if any user data available, If yes I will navigation to Home page else Login page.
Here I'm unable to retrieve stored data, Any inputs please...
Currently using Ionic 2 SQlite plugin.
Note: In browser it's working fine but on Android device it's not working.
app.component.ts : checking user data
loadUser() {
this.userSettings.getUser().then(user => {
this.userObj = JSON.stringify(user);
if (user) {
console.log('App : ', this.userObj);
this.nav.setRoot(HomePage,this.userObj);
} else {
console.log('App : No user data');
this.rootPage = LoginPage;
}
});
}
login.ts : Saving user data
this.userSettings.addUser(
userData.employeeCode,
userData.password,
userData.role
);
user-settings.ts : Storage file in providers
getUser() {
if (this.sql) {
return this.sql.get('user').then(value => value);
} else {
return new Promise(resolve => resolve(this.storage.get('user').then(value => value)));
}
}
addUser(employeeCode, password, role) {
let item = { employeeCode: employeeCode, password: password, role: role };
if (this.sql) {
this.sql.set('user', JSON.stringify(item)).then(data => {
this.events.publish('userObj:changed');
});
} else {
return new Promise(resolve => {
this.storage.set('user', JSON.stringify(item)).then(() => {
this.events.publish('userObj:changed');
resolve();
});
});
}
}
app.module.ts:
providers: [
{ provide: ErrorHandler, useClass: IonicErrorHandler },
AuthService,
SqlStorage,
UserSettings,
Storage
]
Thanks in advance.
Problem solved
After calling the sqlite operation in ngAfterViewInit it's working fine.
ngAfterViewInit() {
this.storage.get('user').then((user: any) => {
if (user) {
this.userCredentials = JSON.parse(user);
this.nav.setRoot(HomePage, this.userCredentials);
}
else {
this.rootPage = LoginPage;
}
});
}
[Source] (https://github.com/driftyco/ionic-conference-app/blob/master/src/pages/account/account.ts)
Cheers :)
As you point out that your code is working in Chrome, but not on your device, you might be calling sqlite before cordova's device.ready() has fired.
In app.component.ts ensure you call this.loadUser() in the following manner: (platform.ready() should already be in the constructor)
platform.ready().then(() => {
this.loadUser();
});

Emberjs: How to redirect to the last accessed route after session invalidated

We are using ember-simple-auth with cookie authentication and we want to redirect to the last accessed route after we login again when the cookie expires. We manage to do the redirection for the following scenarios:
Not authenticated and try to access a route from url
Not authenticated and select an item from the navigation menu
Both, after successful authentication, we redirected to the requested route.
But, we want when our session cookie expired and the user tries to access a route to invalidate the session and redirect the user back to authentication page. When the user log in back we want to redirect him to the requested route. For now we store the previous transition so we can do the redirection but after we invalidate the session the data are lost.
What is the best way to do this?
Our code looks like:
Custom Authenticator
import Ember from 'ember';
import Base from 'ember-simple-auth/authenticators/base';
export default Base.extend({
restore() {
return new Ember.RSVP.Promise(function(resolve, reject) {
let sessionCookie = window.Cookies.get('beaker.session.id');
if(!window.isUndefined(sessionCookie)) {
resolve(true);
}else{
reject();
}
});
},
authenticate(data) {
return new Ember.RSVP.Promise(function (resolve, reject) {
Ember.$.ajax({
type: 'post',
url: '/core/authentication/basic/login',
data: data
}).then((response) => {
resolve({
responseText: response
});
}, (error) => {
reject(error);
});
});
},
invalidate() {
return new Ember.RSVP.Promise(function (resolve, reject) {
Ember.$.ajax({
type: 'post',
url: '/core/authentication/basic/logout'
}).then(() => {
resolve(true);
}, () => {
reject();
});
});
}
});
Application Route:
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
export default Ember.Route.extend(ApplicationRouteMixin, {
session: Ember.inject.service('session'),
beforeModel(transition) {
if(!this.get('session.isAuthenticated') && transition.targetName !== 'core.authentication') {
this.set('previousTransition', transition);
this.transitionTo('core.authentication');
}
},
actions: {
willTransition(transition) {
if (!this.get('session.isAuthenticated')) {
this.set('previousTransition', transition);
} else {
let previousTransition = this.get('previousTransition');
if (previousTransition) {
this.set('previousTransition', null);
previousTransition.retry();
}
}
}
}
});
Authentication Route
import Ember from 'ember';
export default Ember.Route.extend({
session: Ember.inject.service('session'),
actions: {
login() {
let that = this;
let { username, password } = this.controller.getProperties('username', 'password');
let data = {username: username, password: password};
if(this.get('session.isAuthenticated')) {
this.get('session').invalidate();
}
this.get('session').authenticate('authenticator:basic', data).then(() => {
let data = that.get('session.data.authenticated');
// show response message
}, (error) => {
// show error
});
}
}
});
You can add the previous transition inside the session data, like this
this.get('session').set('data.previousTransition', transition.targetName);
because that is still persisted after the session is invalidated.
And then get it back from the store, and do the transition:
this.get('session.store').restore().then(data => {
if (data.previousTransition !== null) {
this.transitionTo(data.previousTransition)
}
})
I solved it by using invalidationSucceded here.
this.get('session').on('invalidationSucceeded', () => this.transitionToRoute('dashboard'))

Ember-data: Saving parent to child via a select box

I've went over a lot of examples both here on SO and in some guides/blogs. Nothing seems to work.
I have a customer that hasMany loads
currently the code is:
route
export default Ember.Route.extend({
setupController: function(controller, model) {
controller.setProperties(model);
},
model: function() {
return Ember.RSVP.hash({
content: this.store.createRecord('truck-load'),
customerList: this.store.findAll('customer'),
equipmentList: this.store.findAll('equipment-list')
});
},
resetController(controller, isExisting) {
if (isExisting) {
var model = controller.get('model');
if (model.get('isNew')) {
model.destroyRecord();
}
}
}
});
select box in the template - materialize add on for ember-cli
{{md-select content=customerList
value=model.customer
label="Customer"
prompt="Please Choose a Customer..."
optionLabelPath='content.name'
optionValuePath='content.id'}}
Current controller - I've tried this many ways
export default Ember.Controller.extend({
actions: {
save() {
var truckload = this.get('model');
this.get('model.customer').then((customer) => {
truckload.set('customer', customer);
truckload.save().then((load) => {
this.get('notify').success('Truck Load Created');
this.transitionToRoute('truck-loads.show', load.id);
});
});
JSON for my JSON-API server running Elixir/Phoenix
Parameters: %{"data" => %{"attributes" => %{"pro_number" => "423432", "special" => nil, "status" => nil},
"relationships" => %{"customer" => %{"data" => nil},
"equipment_list" => %{"data" => nil}}} }
customer (and equipment-list) are both coming over nil.
This fixed it.
1) Settings the drop down result as a controller property
2) Accessing this to lookup the model and set it.
selectedCustomer: null,
selectedEquipment: null,
actions: {
save() {
var truckload = this.get('model');
var customer_id = this.get('selectedCustomer');
var equipment_id = this.get('selectedEquipment')
this.store.findRecord('customer', customer_id).then((customer) => {
truckload.set('customer', customer);
this.store.findRecord('equipmentList',equipment_id).then((equipment) => {
truckload.set('equipmentList', equipment);
truckload.save().then((load) => {
this.get('notify').success('Truck Load Created');
this.transitionToRoute('truck-loads.show', load.id);
});
});
});
return false;
},
I doubt this is the best way to do it - but - it DOES work.

Ember simple auth session content lost after page reload

I've created a clean ember app, installed simple-auth and implemented a custom authenticator for facebook.
https://github.com/prule/ember-auth-spike
I can see that I'm successfully getting the access token from FB and its put in the session (inspecting the container session via chrome ember extension shows me the session is authenticated and the access token is visible).
But when I reload the page in the browser, the session state is lost. Is this expected behaviour? Have I done something wrong in my custom authenticator? The authenticator code is a straight copy and paste (plus some console.logs) from https://github.com/simplabs/ember-simple-auth/blob/master/examples/7-multiple-external-providers.html
Thanks, I appreciate any help.
import Ember from 'ember';
import Base from 'simple-auth/authenticators/base';
export default Base.extend({
restore: function (data) {
return new Ember.RSVP.Promise(function (resolve, reject) {
console.log('restore');
if (!Ember.isEmpty(properties.accessToken)) {
console.log('found access token '+properties.accessToken);
resolve(properties);
}
else {
console.log('no token found');
reject();
}
});
},
authenticate: function (options) {
return new Ember.RSVP.Promise(function (resolve, reject) {
console.log('1');
FB.getLoginStatus(function (fbResponse) {
console.log('2');
console.log(fbResponse);
if (fbResponse.status === 'connected') {
Ember.run(function () {
console.log(fbResponse.authResponse.accessToken);
resolve({accessToken: fbResponse.authResponse.accessToken});
});
}
else if (fbResponse.status === 'not_authorized') {
reject();
}
else {
FB.login(function (fbResponse) {
if (fbResponse.authResponse) {
Ember.run(function () {
console.log(fbResponse.authResponse.accessToken);
resolve({accessToken: fbResponse.authResponse.accessToken});
});
}
else {
reject();
}
});
}
});
});
},
invalidate: function (data) {
return new Ember.RSVP.Promise(function (resolve, reject) {
FB.logout(function (response) {
Ember.run(resolve);
});
});
}
});
The argument to the authenticator's restore method is called data but you're checking for properties.accessToken. This should actually raise an error anyway as properties is undefined there.