Injecting NavController in constructor of service fails with no provider error. Can someone please provide a workaround for this?
NavController is NOT meant to be injected into the Service class because this is not their intended purpose. The service shouldn't be responsible for displaying alerts/loading/ or any component that needs to be activated by nav. A service should just be for getting and returning data. Anything else should be done within the component.
Following is the guideline with services:
It's bad practice to change a view from a service (broken MVC).
However, you could send events from services to the main controller,
and the controller can use NavController (best way), or you could send
NavController to your service like an attribute (not bad way...). Or
you may need to create a component instead of using the service.
You can not use NavController in service by normal way. You should do like that:
import { App} from 'ionic-angular';
constructor(private app: App){
}
gotoPage(page: any){
this.app.getRootNav().push(page);
}
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.
To learn more about using services and components, I'm trying to set up a simple flash-message style service. Within my route, I'm saving a record and receiving either a json notice or json error from the server.
Since this is a behavior I'd eventually like to use app-wide, I'm using a simple service (injected into my routes) to handle displaying the message. Within a route, I'm able to call this.get('notification').displayMessage(msg).
Currently the displayMessage function within the service is just alerting the message because I'm stuck on how to create a component that the service can "update". How can a service communicate with a component so that I can send a message and display it from the component template?
profile/index route
user.save().then( (response) => {
//display response.notice in the app-notification component template
}, (response) => {
let errors = JSON.parse(response.errors);
//display response.error in the app-notification component template
this.get('notification').displayMessage(errors[0]);
}
service
import Ember from 'ember';
const { Service } = Ember;
export default Service.extend({
displayMessage(msg) {
alert("message ---> " + msg);
}
});
component
???
component template
<h2 class="alert">{{message}}</h2>
application template
{{app-notification message=message}}
In terms of accessing the service, I like the example that they using the docs: http://guides.emberjs.com/v2.1.0/applications/services/
The ShoppingCart service is injected into components that need to access the Cart.
Once you have access to the ShoppingCart you should be able to:
set a Notification in the service for User from your route error catch.
set up a Computed Property based on the Notification service (some sort of hasNotification method) on the Component hasError that can toggle the error message.
As soon as you set a notification your component will see that the property it is watching has changed and will show/hide your notification.
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.
I have a again which I can't answer for my self properly, maybe because of my lack in expierience with EmberJS.
I have to develop a management interface in EmberJS, using Symfony 2 for the backend, which should act and feel like a desktop application. So far so good, but since alot of people will work with the data inside this application, i would really like to use a WebSocket adapter implementation for EmberJS, since every connected client should always know about changes in entities immediately (or asap). I could write a WebSocket adapter for EmberJS but my problem here is that the WebSocket will do much more then RESTful operations, also the server will send messages without any EmberJS request (e.g. an entity changed and the server broadcasting this change to all clients). That means that i need a "command" structure on top of RESTful operations which, as far as my expierience goes, will not work with a pure DS Adapter.
For example:
Maybe i will trigger a controller method that will send a websocket message like this:
{command: "say", parameters: {message: "Hello guys!"} }
This command is not Entity (DS) related and will never go into the application store.
Another example would be like this:
{command: "load entity", parameters: {type: "Vendor\Bundle\Entity\Type", id: 43} }
Which would load an entity which should be stored in the application store.
Well, as i said, im not that familiar with EmberJS that I could figure out which the best approach could be. Should I bypass the DS Adapter completely and check for "isDirty" and just the push methods after loading entities? I'm happy about any idea you have!
As far as I understand your question, you want to push changes from your backend to your single page app?
You can push custom JSON into your application's store in Ember by using self.store.push('modelName', json). Have a look at the docs for a better undestanding.
So for example if your server sends you JSON via websocket that looks like this
{
- "message": {
"type": "fooModel",
"data": {
... // Model attributes here
}
}
}
you can push the data into your store. The following snippet would work with SocketIO for example:
App.ApplicationRoute = Ember.Route.extend({
activate: function() {
// connect to the websocket once we enter the application route
var socket = window.io.connect('http://localhost:8080');
var self = this;
socket.on('message', function(data){
self.store.push(data.type, data.item);
});
}
});
You can easily modify this snippet to fit your needs.
Trying to understand better about ember's register and inject.
Basically my code looks like this:
//creating a service
Nerdeez.Wormhole = Ember.Object.extend({
...
})
//registering this service as a singleton
App.register('wormhole:current', Nerdeez.Wormhole, {singleton: true});
//wanting to inject this service to be available everywhere in my application
//especially in the adapter where i use it in the ajax hook
App.inject('App', 'wormhole', 'wormhole:current');
//when trying to access this service in the ajax hook in the adapter i get undefined WTF!
App.get('wormhole') === undefined //true
i just want this service available globally in the entire application as a singleton, what is the best way to achieve this?
it's important to say that i manage to inject my service to models, views, and controllers and the problem is injecting it to my adapter.
Thanks in advance
I couldn't figure out a way to inject the object into App either, but you can inject it into the adapter (or store) just like you can with for route & controller objects:
// register
App.register('wormhole:current', Nerdeez.Wormhole);
// inject into adapter
App.inject('adapter', 'wormhole', 'wormhole:current');
// inject into store
App.inject('store', 'wormhole', 'wormhole:current');
// inject into routes & controllers
App.inject('route', 'wormhole', 'wormhole:current');
App.inject('controller', 'wormhole', 'wormhole:current');