Why can't I inject a service into a page?! (JavaScript)


#1

Well, I’ve searched forums and read the documentation, this simply makes no sense to me, I must be missing something.

I’m trying to make a very simple app as a learning experience for Angular2/Ionic2, an alarm clock app. I want an alarm service to keep my logic and local storage access out of the page, and yet, I cannot inject it. Please help!

I started with the default tabbed layout in Ionic, so I have a page1, page2, and page3 folder. In the page1 folder I added: alarm.service.js, and that file looks like this:

import {Injectable} from 'angular2/core';

@Injectable()
export class AlarmService {
 constructor() {
   alert('worked');
 }
}

I tried to keep it as absolutely simple as possible for testing, just pop up an alert when it’s created.
Then in page1.js I’ve tried a number of things actually based on the ionic troubleshooting guide and various forum posts, and nothing works. Here’s what it looks like right now:

import {Page} from 'ionic-angular';
import {AlarmService} from './alarm.service';

@Page({
  templateUrl: 'build/pages/page1/page1.html',
  providers: [AlarmService]
})
export class Page1 {
  constructor(@Inject(AlarmService) alarmService) {}
}

I added the “providers: [AlarmService]” based on a post in a forum, the troubleshooting guide doesn’t show it. I really don’t understand why something so simple is so difficult…

Am I missing something obvious?

Thanks,
Rob


#2

Use console.debug instead of alert and, if you use TypeScript, the right syntax is:

export class Page1 {
  constructor(alarmService: AlarmService) {}
}

PS if you want use @Inject then you need import it too


#3

Hey, thanks for the reply. I am not using Typescript, just regular JS, and per the troubleshooting guide it said if I did that use the @Inject syntax. You are right about missing the import, I have added the line:

import { Inject } from 'angular2/core';

I also tried importing it from ionic-angular. I’m not sure which is the correct place but neither seems to work. I also tried console.log but…

Let me be more specific about my error (I should have done that in the first place). In my console window where I ran ionic serve I see this:

ERROR in ./app/pages/page1/page1.js
Module build failed: SyntaxError: D:/Projects/kitten-alarm-clock/app/pages/page1/page1.js: Unexpected token (9:14)
})
export class Page1 {
  constructor(@Inject(AlarmService) alarmService) {}
}

    at Parser.pp.raise (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:1378:13)
    at Parser.pp.unexpected (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:2817:8
)
    at Parser.pp.parseBindingAtom (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:
1536:12)
    at Parser.pp.parseMaybeDefault (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js
:1575:23)
    at Parser.pp.parseBindingList (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:
1558:23)
    at Parser.pp.parseMethod (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:1092:
22)
    at Parser.pp.parseClassMethod (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:
2495:8)
    at Parser.pp.parseClassBody (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:24
56:10)
    at Parser.pp.parseClass (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:2339:8
)
    at Parser.pp.parseStatement (D:\Projects\kitten-alarm-clock\node_modules\babel-core\node_modules\babylon\index.js:18
13:19)
 @ ./app/pages/tabs/tabs.js 12:12-37

It seems it doesn’t like the ampersand, even though the ionic docs say to use it…I don’t know.
In chrome in the console I get the following errors:
app.bundle.js:63648Uncaught Error: Cannot find module "…/page1/page1"webpackMissingModule @ app.bundle.js:63648(anonymous function) @ app.bundle.js:63648__webpack_require__ @ app.bundle.js:20(anonymous function) @ app.bundle.js:3191__webpack_require__ @ app.bundle.js:20(anonymous function) @ app.bundle.js:50__webpack_require__ @ app.bundle.js:20(anonymous function) @ app.bundle.js:40(anonymous function) @ app.bundle.js:43
?ionicplatform=android:54 Uncaught ReferenceError: ionic is not defined(anonymous function) @ ?ionicplatform=android:54
app.bundle.js:63648 Uncaught Error: Cannot find module "…/page1/page1"webpackMissingModule @ app.bundle.js:63648(anonymous function) @ app.bundle.js:63648__webpack_require__ @ app.bundle.js:20(anonymous function) @ app.bundle.js:3191__webpack_require__ @ app.bundle.js:20(anonymous function) @ app.bundle.js:50__webpack_require__ @ app.bundle.js:20(anonymous function) @ app.bundle.js:40(anonymous function) @ app.bundle.js:43
?ionicplatform=ios:54 Uncaught ReferenceError: ionic is not defined(anonymous function) @ ?ionicplatform=ios:54
undefined:1 Uncaught (in promise) TypeError: object is not a constructor
at then (native)

I guess this makes sense that it can’t find the module because I’m causing a module build error. But I don’t know why it doesn’t like the ampersand.


#4

I think that in JavaScript you could inject a service this way:

export class Page1 {
  static get parameters() {
    return [[AlarmService]];
  }

  constructor(alarmService) {}
}

#5

Sorry, I’m use TS, so i don’t know all nuances of native js. But people use static get parameters()


#6

Thank you everyone for your replies. You were both correct about the static get parameters piece, and thank you @iignatov especially for the example. The final working code looks like this:

import {Page} from 'ionic-angular';
import {Inject} from 'angular2/core';
import {AlarmService} from './alarm.service';

@Page({
  templateUrl: 'build/pages/page1/page1.html',
  providers: [AlarmService]
})
export class Page1 {

  static get parameters() {
    return [[AlarmService]];
  }
  constructor(alarmService) {}
}

However I think the real lesson here is…use TypeScript. All the Angular 2 docs are TypeScript (There’s an option for JS but most of the content isn’t there yet), and it seems much cleaner than this code. Also, it would be nice if Ionic changed their troubleshooting guide to show this.

But, thank you both again for helping me out, it was a good learning experience.


#7

One other thing, although it may be outdated at this point. The @Injectable decorator at least used to be a bit counterintuitive. One would think it would be used as you did, on the class being injected. However, it needs to go on the class that requires DI to inject things into its constructor (Page1 in this case).