At the moment, I handle invalid routes in Ember.js like this:
this.route('invalid', { path: '*path' }
This works and applies to routes like:
https://www.appname.com/#/misspelled_name
However, when using Dropbox Datastores API, I am having some problems. After an authentication request, Dropbox redirects me to:
https://www.appname.com/#access_token=...
Is there a way to handle this route? Without the slash before the route name? In this case, the 'invalid' route is not applied and I receive an error 'The route access_token=... was not found'. How should I handle this response in Ember?
UPDATE
I don't think it is possible to handle this. The only working solution for me was to do authentication before Ember was even loaded. After successful authentication, I load my ember app:
window.dropboxClient = new Dropbox.Client({
key: 'some_key'
});
dropboxClient.authenticate({ interactive: true }, function(error) {
if (error) {
return console.log('Error during authentication');
}
});
yepnope([{
test : window.dropboxClient.isAuthenticated(),
yep : ['my-ember-app.js']
}])
I don't have direct experience with EmberJS, but one possibility might be to run client.authenticate({ interactive: false }); before the EmberJS script is even loaded.
Another alternative is to specify a different redirect URI (not the same page as the rest of your app) and not load EmberJS on that page. (That page would then presumably redirect back to the main app when it was done.) You could also forgo redirects altogether and use the pop-up auth driver instead.
Before the #/, you aren't actually inside of the ember app. As a result, none of the ember code will have any impact on this.
Related
According to the docs, you just need to embed the analytics code and reopen the Router. The latter seems unclear to me.
I've placed the embedded code on index.html, then created the following
app/reopens/router.js
import Router from '../router';
Router.reopen({
notifyGoogleAnalytics: function() {
return ga('send', 'pageview', {
'page': this.get('url'),
'title': this.get('url')
});
}.on('didTransition')
});
app/app.js: Added the import...
import './reopens/router';
This results in a fatal error when viewing the site: Uncaught ReferenceError: ga is not defined
How do you make the ga function visible to this observer?
The problem is that on the first run through of the didTransition, the method is missing as that part of the script has not been executed.
Is this a problem? Actually no. The purpose of didTransition in this instance is to capture when a transition occurs as the supplied javascript from Google with capture to initial local of the page. All is needed is a check to see if 'ga' exists.
Add the recommended javascript to the index.html of your ember app from Google (https://developers.google.com/analytics/devguides/collection/analyticsjs/).
Modify your code to include a check to see if ga is undefined:
import Router from '../router';
Router.reopen({
notifyGoogleAnalytics: function() {
if (typeof ga != 'function') { return; }
return ga('send', 'pageview', {
'page': this.get('url'),
'title': this.get('url')
});
}.on('didTransition')
});
This is variation of what I have for an ember-cli based app. Let me know if it works.
After looking, exhaustively, for a way to plug Google Analytics into Ember, I built my own. For all those still struggling with this issue and not finding the Ember.js v1.0.0 answer helpful, here is how I got it to work on v4.2:
import Route from '#ember/routing/route';
import { action } from '#ember/object';
export default class ApplicationRoute extends Route {
#action
didTransition() {
gtag('set', 'page_path', window.location.pathname);
gtag('event', 'page_view');
return true;
}
}
Forgive my ignorance, as I am new to Ember, but the existing documentation makes it look like didTransition is no longer supported at the router level. That makes +99% of the solutions I found on the internet outdated.
Instead, I invoked didTransition at the route level. By extending Route as ApplicationRoute, I extended the main behavior of every Route. In this example, I execute the gtag event for triggering a page view after setting the page URL. The gtag code from Google simply goes in the index.html file in the head section.
Hopefully, this saves someone from hours of searching.
I am learning Ember and I am getting stuck on making the mock api with ember-cli-mirage. I modified the config file as specified in the ember tutorial as well as on the ember-cli-mirage site, but everytime I hit the endpoint I get nothing. Here is my current config file
export default function() {
this.get('/api/users', function() {
return {
users: [
{id: 1, name: 'Zelda'},
{id: 2, name: 'Link'},
{id: 3, name: 'Epona'},
]
}
});
}
Like I said, when I go to /api/users it is just a blank page. Am I missing something here?
Thanks!
First thing first, install Ember inspector extension (for Chrome or Firefox) and look in the browser console to see if Mirage is giving you some errors. If nothing is written in there, you are not hitting the endpoint with your ember application. Basically, Mirage proxies all the request from your ember application.
So you need to generate a user model
ember g model user
and put in there the name attribute.
Create a route and in the model hook write
return this.get('store').findAll('user');
(look at the quick start tutorial if something is not clear)
So now, leveraging Ember Data, your app will request all users hitting on /users.
Now let's start with mirage, generate a mirage model
ember g mirage-model user
and follow the mirage quickstart, just adapt it to your needs :)
Start your application with ember s and you should see the request to /users.
If you want to put your api on the same domain, but with the /api prefix, then i suggest you to read about endpoint path customization
In app/mirage/config.js you can set up mock endpoints for your users:
export default function() {
this.get('/users');
this.post('/users');
this.put('/users/:id');
this.del('/users/:id');
}
You can set up your mock data by configuring fixtures in app/mirage/fixtures/users.js:
export default [
{id: 1, name: 'Zelda'},
{id: 2, name: 'Link'},
{id: 3, name: 'Epona'},
];
Mirage isn't an actual server, so you won't be able to hit the API from your browser directly. It's a mock server that lives in JavaScript memory, and is instantiated when your Ember app boots up.
To test out your mocks, have your Ember app make an API request, e.g.
// routes/application.js
export default Ember.Route.extend({
model() {
return Ember.$.getJSON('/api/users');
}
});
If everything's hooked up correctly, you should now see Mirage handling this request and logging the response data in your console.
There seems to be a lot of discussion on SO (e.g. these questions: A, B, C, D) and other sites (e.g the Ember docs) about configuring Ember to allow cross-origin requests. That's all fine and well, but I'd rather have Ember's back-end do the work of communicating with a remote service (Ember's server-side components to make the request, rather than the user's browser). Is this documented? Can someone provide an example?
I thought I would find it easy to modify the HTTP server backing the ember serve command. Instead, I used the --proxy flag from Ember's CLI. It allows you to use remote services to provide data.
For this to work, let's assume a remote server foo.com:3000 provides JSON data at the path /resource. Configure a controller to GET the data like so:
import Ember from 'ember';
function getRemoteResource(store){
var dfd = Ember.$.Deferred();
Ember.$.ajax('/resource')
.done(function(data){
store.createRecord('model', data);
dfd.resolve();
})
.fail(function(err){
dfd.reject(new Error("An error occurred getting data.", err));
});
return dfd.promise();
}
export default Ember.Controller.extend({
actions: {
getResource:function(){
var dataStore = this.store;
return getRemoteResource(dataStore);
}
}
});
Use a template like this to invoke the controller's action:
<h2>Remote data example</h2>
<button class="my-button" {{action 'getResource' }}>
Get resource
</button>
Assuming your code is on host bar.com, start ember like this : ember serve --proxy http://foo.com:3000. Then, open your browser to the appropriate page that loads the template (somewhere like http://bar.com:4200/index) , click the button and see that remote data is loaded.
So according to Ember's documentation Ember defaults to using the hashchange event. Thats why we have the fancy #/some/url setup. We can also set it to use the browser's history API.
I've noticed that most (if not all) sites listed on Built with Ember apparently use the history API. Which makes sense because it make the URL look more natural.
All that is to say I (sorta) understand where, how, and why the # gets tacked on.
My question relates specifically to EmberCLI. I've noticed that when I create a simple app the # is not in the URL. Is that because I havent deployed it yet? Or does the CLI default to the history api? If so, where is this set? I cant find an instance of
App.Router.reopen({
location: 'history'
});
The first one I clicked used hash history ;) https://fnd.io/
By default Ember uses the hash change event, mostly due to cross browser compatibility. http://caniuse.com/history
In ember-cli it uses auto by default. http://emberjs.com/api/classes/Ember.Location.html#toc_autolocation
If you look in router.js you'll notice
var Router = Ember.Router.extend({
location: YourAppENV.locationType
});
which pulls its settings from config/environment.js
module.exports = function(environment) {
var ENV = {
baseURL: '/',
locationType: 'auto',
EmberENV: {
....
Just as a quick plug, location history is a tad more difficult to set up, since you
essentially have to tell your server to serve from the base page whenever it's hit, and ignore anything after that, but it's really just a one time setup.
For locationType: 'auto'
Your routes will be http://localhost:4200/login
For locationType: 'hash'
Your routes will be http://localhost:4200/#/login
That's it.
I am new to Ember-js, I was recently going through some blog entries and also saw the video of Ember-js introduction by Tom dale.
to summarize they say that Router Api is newly introduced and it the best thing that happened to Ember-js,Router Api is used to manage the state of the application and each state is identified with a URL, now for a single page application where in we use only one URL, what is the role of the router, will there be only one routeing entry which is mapped to '/'(index)? If yes, then we lose the advantage provided by the Router api right?
now for a single page application where in we use only one URL, what is the role of the router, will there be only one routeing entry which is mapped to '/'(index)?
Typically a single page application will still use the url. For example watch url change when using gmail. So in this case single page application means the browser doesn't fetch a new page as url changes. Like gmail, a typical ember single-page application will change url as user navigates to various parts of the application. The ember router takes care of this automatically.
If yes, then we lose the advantage provided by the Router api right?
If you decide not to use the url, and really want it to just stay "/" the whole time, you can still use the router. Just set the router's location type to "none"
See http://emberjs.com/guides/routing/specifying-the-location-api/
I understand that routing here means managing states, but at any point of time user can be in a set of states for instance take gmail the user would be in login state and compose state, how to manages multiple states existing together?
For sure that is true. The ember router is basically a statechart where routes (leaf nodes) are nested under some number of resources. So in the case of gmail for example only a logged in user can be in the compose state.
GMail URL: https://mail.google.com/mail/u/0/?shva=1#inbox
// Gmail Routes:
* /mail - the mail application
* /u/0 - connected account index 0 for the current user
* ?shva=1 - http://stackoverflow.com/questions/1692968/what-is-shva-in-gmails-url
* inbox - folder name
EmberMail Version: https://mail.ember.com/mail/u/0/inbox
// EmberMail Routes
this.resource('mail', { path: '/mail' }, function() {
this.resource('currentUser', { path: '/u' }, function() {
this.resource('account', { path: '/:account_id' }, function() {
this.route('folder', { path: '/:folder_id' });
});
});
});
can you point me to a example application which uses routing extensively?
The best example I know of is discourse. Check out the following for example of how a large ember application uses the ember router:
Discourse Application routes
Discourse Admin routes