I'm having the hardest time getting typescript and ember to work together. I got all the definition files in definitely typed and I went through the ToDo walk throughs on Ember guide on the site. I'm trying to convert the js to typescript and see what the best way to go about setting up the project was, but I guess I'm not understanding the typescript definition very well.
If I do:
/// <reference path="typings/ember.d.ts" />
var App = Ember.Application.create();
App is a type of '{}' and I can't access 'Routers' to do the next line of the guide
App.Router.map( ... )
The best thing I found online was this which doesn't work with the current typing.
I've seen the typescript ember-app-kit but it doesn't really help since it barely includes any typescript and their setup is barely like the ember guides. I just need to be pointed in the right direction. Thanks guys.
I'm not familiar with Ember, but from inspecting ember.d.ts, I can see that create() is defined as a static generic function on object:
static create<T extends {}>(arguments?: {}): T;
So then you should be able to get better type information by passing an actual type:
var App = Ember.Application.create<Ember.Application>();
However, I see also that the ember typedef doesn't include a "Router" member in the application class, and even if it did, the Router class does not define map(). I was able to get it to work by creating an extended type definition:
// ./EmberExt.d.ts
/// <reference path="typedef/ember/ember.d.ts" />
declare class RouterExt extends Ember.Router {
map: ItemIndexEnumerableCallbackTarget;
}
declare class ApplicationExt extends Ember.Application {
Router: RouterExt;
}
And then referencing that from my combined router/application file:
/// <reference path="typedef/ember/ember.d.ts" />
/// <reference path="./EmberExt.d.ts" />
var App = Ember.Application.create<ApplicationExt>();
App.Router.map(function () {
this.resource('todos', { path: '/' });
});
After doing this, it compiles and loads without error, though it doesn't actually do anything (which I believe is ok for this phase of the walkthrough)
Full and mostly-accurate type definitions for Ember.js are now available to install from npm at #types/ember, #types/ember-data, and so on, currently all via the Definitely Typed project.
Ember CLI integration is available through the ember-cli-typescript addon. The easieset way to configure a Ember.js project with TypeScript is to run ember install ember-cli-typescript in the root of your Ember.js project. Doing so will automatically generate a tsconfig.json which handles Ember’s conventional project layout correctly (for apps, addons, and in-repo addons). It will also install the type definitions for all the core Ember projects automatically.
Related
Having a hard time finding out where a helper not in app/helpers is defined. The helper was very generically named, I searched my package.json for the helper name but there was nothing. I was stuck hunting around with google to try and figure out what addon defined it.
Given some helper ({{totally-generic-name param1="foo"}}) how would one go about finding where it's defined?
(I happen to be on Ember 2.13)
(Note: the helper was contains defined in ember-composable-helpers, so it would have been a LITTLE helpful to search package.json for "helper" but that is a pretty tedious in-direct way of searching, which have may not even yielded the answer)
For me the easiest way is to run a development build of your application (ember serve), open development tools of your browser and open a file called <your-app-name>/helpers/<helper-name>.js. In the first line of the file, you see from where it is imported.
Let's assume your application name is foo and you have installed ember-array-helper. Run your application via ember serve and open it in Chrome. Go to development tools Source section. Search for helpers/array.js in subsection Network. You could search for a file per name via ctrl+p. If the helper is provided by an addon this file is autogenerated. It looks like the following:
define('foo/helpers/array', ['exports', 'ember-array-helper/helpers/array'], function (exports, _array) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, 'default', {
enumerable: true,
get: function () {
return _array.default;
}
});
});
In first line your read the name of the import ember-array-helper/helpers/array from which you can guess on the addon name (first part). Note that you could also open the actual helper exported by addon via developer tools by opening /assets/addon-tree-output/ember-array-helper/helpers/array.js. Since the last part is coming from the import, you could easily use that one to search for the file. Now place your breakpoints and inspect this code as much as you like.
The same approach should work in all major browsers.
I'm adding unit tests to an Ionic 2.2.0 app I manage, but my Components crash at test-time when they encounter Google Analytics code. I'm using Ionic's official unit testing example as a basis, and my current progress can be seen on our public repo.
My project uses Google Analytics, which is added to the HTML and downloaded at runtime (because we have different keys for development vs production).
The code that initializes Analytics is in my main.ts, and it sets a global variable ga, which is subsequently available throughout the application.
I'm beginning the tests for the app's first page, which uses Analytics. When I run the tests, I'm met with the following error
Component should be created FAILED
ReferenceError: ga is not defined
at new MyBusesComponent (webpack:///src/pages/my-buses/my-buses.component.ts:33:6 <- karma-test-shim.js:138419:9)
at new Wrapper_MyBusesComponent (/DynamicTestModule/MyBusesComponent/wrapper.ngfactory.js:7:18)
at CompiledTemplate.proxyViewClass.View_MyBusesComponent_Host0.createInternal (/DynamicTestModule/MyBusesComponent/host.ngfactory.js:15:32)
........
This is because main.ts doesn't seem to be loaded or executed, and I assume TestBed is doing that purposefully. It's certainly better that I don't have the actual Google Analytics object, but the Component does need a function called ga.
My question, therefore, is as follows: how can I create Google Analytics' ga variable in my test configuration such that it's passed through to my components at test-time?
I've tried exporting a function from my mocks file and adding it to either the imports or providers arrays in my spec file, but to no avail.
I appreciate any advice! Feel free to check my code at our repo I linked to above and ask any followups you need. Thanks!
You declare the var ga but that is just to make TypeScript happy. At runtime, the ga is made global from some external script. But this script is not included in the test.
What you could do is just add the (mock) function to the window for the tests. You could probably do this in your karma-test-shim.js.
window.ga = function() {}
Or if you wanted to test that the component is calling the function with the correct arguments, you could just add the function separately in each test that uses the function. For example
beforeEach(() => {
(<any>window).ga = jasmine.createSpy('ga');
});
afterEach(() => {
(<any>window).ga = undefined;
})
Then in your test
it('..', () => {
const fixture = TestBed.creatComponent(MyBusesComponent);
expect(window.ga.calls.allArgs()).toEqual([
['set', 'page', '/my-buses.html'],
['send', 'pageview']
]);
})
Since you're making multiple calls to ga in the constructor, the Spy.calls will get the argument of all each call and put them in separate arrays.
What is the correct way of placing your helper files and also where should they go with respect to the resolver finding them from an addon ember-cli project?
I am running ember-cli 0.2.2.
I generated an helper from an addon project with:
ember g helper display-helper
The generator placed the file in app/helpers which seemed wrong to me, I would have thought that it should have been placed in addon helpers. I moved the file to addon/helpers and it looks like this:
export default Ember.Handlebars.registerBoundHelper('displayHelper', function displayHelper(searchPath) {
return new Ember.Handlebars.SafeString(get(this, searchPath));
});
When I ran ember test I get the following output:
✘ Error: Assertion Failed: A helper named 'displayHelper' could not be
found
The only way I get this helper to be found by the resolver is to add an import that references the helper in a component that is using it like this:
import displayHelper from '../helpers/display-helper';
This does not seem correct, I would have thought the resolver would have found this automatically?
Also even if I have the reference, the following code ends up with the same error message as above:
import Ember from 'ember';
var get = Ember.get;
function displayHelper(context, searchPath) {
return new Ember.Handlebars.SafeString(get(context, searchPath));
}
export default Ember.Handlebars.makeBoundHelper(displayHelper);
So to sum up, I have to have this line in the component whose template uses the helper:
import displayHelper from '../helpers/display-helper';
And I have to use registerBoundHelper and not makeBoundHelper like the docs say or the helper cannot be found.
If you move your helper from app/helpers to addon/helpers, it is not available in your app namespace. To fix this, add the following file:
// app/helpers/display-helper.js
import displayHelper from 'your-addon-name/helpers/display-helper";
export default displayHelper;
(Do not copy your-addon-name literally, use the name of your addon, which is also your addon's namespace.)
This is based on the instructions here:
http://www.ember-cli.com/#addon-components
Just like the example component there, you can put your real helper code in addons/helpers/display-helper, but you need to import and reexport it to your app for your resolver to find it.
I try to make an addon using ember-cli. Here it is step by step what I have done so far:
sudo ember addon test-addon
cd test-addon
sudo ember serve
now the server runs and on localhost:4200 I can see the test/dummy app's application hbs.
Welcome to Ember.js
Its time to make some components for the addon:
sudo ember g component my-form
In the tests/dummy/app/templates/application.hbs I added
{{my-form}}
And now I'm getting the following js error:
Uncaught Error: Could not find module test-addon/components/my-form imported from dummy/components/my-form
edit
After struggling a little bit with npm, I tried it again (without sudo) and the same thing happened. I'm on Ember CLI 0.2.1. Here are my files, but they should be the same since they are auto-generated. The error is thrown from bower-components/loader.js/loader.js line 110.
addon/components/my-form.js
import Ember from 'ember';
import layout from '../templates/components/my-form';
export default Ember.Component.extend({
layout: layout
});
addon/templates/components/my-form.hbs
{{yield}}
app/components/my-form.js
import myForm from 'test-addon/components/my-form';
export default myForm;
It looks like (as of July 2015, anyway) that the fact templates don't work in addons is partially by design. Philosophically, I guess the justification is that the styling should be app-specific, but the JS logic can be shared. Or it's just a bug/oversight.
It turns out that if you simply remove that layout line and the import layout, it will work.
So the result looks like:
<app-name>/app/templates/includes-a-shared-component.hbs:
What follows is my shared component! {{my-shared-component}}
<addon-name>/addon/components/my-shared-component.js:
import Ember from 'ember';
export default Ember.Component.extend({
valueFromProperty:function() { // simple hello-world-style function
return 5;
}.property()
});
<app-name>/app/templates/components/my-shared-component.hbs:
Hey look I'm the app-specific style for your component <marquee>Hello world</marquee>
Here's a value from a property: {{valueFromProperty}}
My versions:
Ember: 1.13.1
node: 0.12.0
npm: 2.12.1
And here's a very different (and IMO better, but not perfect) answer than my earlier one.
<addon-name>addon/components/test-component.js:
import Ember from 'ember';
export default Ember.Component.extend({
valueFromProperty:function() {
return 5;
}.property(),
layout:Ember.HTMLBars.compile("I'm the addon's layout {{valueFromProperty}}")
});
You will need to add the template compiler to your app:
<app-name>/app/ember-cli-build.js:
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
// Add options here
});
app.import('bower_components/ember/ember-template-compiler.js');
... other stuff...
Note that the layout property in the addon's component completely overrides your in-app template, so per-app customizing becomes more difficult. But if you want your template customizable, you could probably use my other answer where you don't specify layout at all and just let the resolver find the template in your app.
One more approach I've found that works and is different than my other answers.
Let's say you've done ember g component my-addon-component in your addon.
This will result in you having a component at: <addon-name>/addon/components/my-addon-component.js and a template at <addon-name>/addon/templates/my-addon-component.hbs (at least with my current ember-cli).
You'll also have a tiny component stub at <addon-name>/app/components/my-addon-component.js
The fix:
1. Move the component guts from <addon-name>/addon/components to <addon-name>/app/components (replacing the stub).
2. Move the template from <addon-name>/addon/templates/components to <addon-name/app/templates/components
After 1: The import layout from ../templates/components/my-addon-component will now have a different meaning: it'll be importing from the including-app's namespace instead of the addon's namespace.
After 2: The template's import location will be in the including-app's namespace. This also seems to mean it gets compiled by the app, so you won't throw the "addon templates were detected, but there are no template compilers registered"
I have just started to refactor our Ember application to use Pods so that our directory/file structure is more manageable. At the same time i have upgraded Ember-Cli so I am running with the following configuration:
Ember : 1.8.1
Ember Data : 1.0.0-beta.12
Handlebars : 1.3.0
jQuery : 1.11.2
I have updated the the environment.js to include the following
modulePrefix: 'emberjs',
podModulePrefix: 'emberjs/pods',
I have also tried to set it to 'app/pods' and just 'pods' but with no luck.
The directory structure is as follows:
emberjs/
app/
controllers - original location, still has some original controllers here for other parts of the system
pods/
job/
parts/
index/
controller.js
route.js
template.hbs
edit/
controller.js
route.js
template.hbs
The application build ok and if i look in the emberjs.js file i can see the various defines for the pods controllers, routes and templates
e.g.
define('emberjs/pods/job/parts/index/controller', ['exports', 'ember'], function (exports, Ember) {
define('emberjs/pods/job/parts/index/route', ['exports', 'ember'], function (exports, Ember) {
define('emberjs/pods/job/parts/index/template', ['exports', 'ember'], function (exports, Ember) {
so something is recognising the pods structure.
But the problem comes when I try to access this route. I get a warning message in the console and get nothing displayed - basically it says it can find the template abd it looks like it is using an generated controller.
generated -> controller:parts Object {fullName: "controller:parts"}
vendor-ver-1423651170000.js:28585 Could not find "parts" template or view. Nothing will be rendered Object {fullName: "template:parts"}
vendor-ver-1423651170000.js:28585 generated -> controller:parts.index Object {fullName: "controller:parts.index"}
vendor-ver-1423651170000.js:28585 Could not find "parts.index" template or view. Nothing will be rendered Object {fullName: "template:parts.index"}
vendor-ver-1423651170000.js:28585 Transitioned into 'jobs.job.parts.index'
If I look in the Ember inspector in Chrome I see that in the Routes section it shows parts/index to have route of parts/index controller as parts/index and template as parts/index.
Is this what I should expect?
I am not sure how Ember resolves the various parts when using pods.
To test this out I put a copy of the template in the templates/parts directory and reloaded it. This time it found the template and rendered it but lacking the data - probably due ti it using the default route and controller.
Does anyone any idea what I am doing wrong. have I missed out a step somewhere, or configured it incorrectly?
Try removing old routes/controllers/templates when adding new ones. Don't keep two copies.
Also it could be unrelated to your files structure. Try creating a blank app and copying files one by one, to see when the issue starts to happen. Use generators and then overwrite the generated files with yours if possible.