How to select EmberJS elements with puppeteer - ember.js

Okay, I'm currently stuck. I'm trying to implement CucumberJS and Puppeteer on an EmberJS solution.
I've got a emberjs button:
{{#ao-button data-test-button-view-related-payments-requests="true" isFluid=true size="large" type="primary" action=(route-action 'viewRelatedRequests' upload)}}<span class="ao-button__label" >View Related Payment Requests</span>{{/ao-button}}
and I included an HTML attribute: data-test-button-view-related-payments-requests="true"
When I attempt tp select it:
await this.page.click('[data-test-button-view-related-payments-requests="true"]');
I get:
Error: No node found for selector: [data-test-button-view-related-payments-requests="true"]
What am I doing wrong?

Custom data-* attributes must be enabled in order to pass them to a component. This is done by extending the component and then adding attribute bindings. See this section of the Guides. Example:
import LinkComponent from '#ember/routing/link-component';
export default LinkComponent.extend({
attributeBindings: ['data-toggle', 'lang']
});

Related

In Ember, why does my template want {{model.key}}, not just {{key}}?

I am trying out Ember, and finding a discrepancy with the docs. I used the Ember CLI to ember generate template index and ember generate route index. Then I set up a trivial model in index.js:
model: function () {
return {name: "Joe"};
}
From my reading of the docs and examples, I expected to be able to access this value simply with {{name}} in my index.hbs template, but instead I only get the value with {{model.name}}. Why?
Before Ember 1.11 you could use ObjectController, that works like a proxy to corresponding route model, and you could write {{name}} for model.name.
ObjectController was deprecated in Ember 1.11, details here:
http://emberjs.com/deprecations/v1.x/#toc_objectcontroller. So in last Ember versions you should use Controller class instead ObjectController, that doesn't work as proxy of model. You could think of it as of Ember Object with model property from corresponding route. So {{name}} means property of Controller, {{model.name}} - property of model.
For example:
//route
model: function () {
return {name: "Joe"};
}
//controller
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'Marry'
});
//template
{{name}} //=> Marry
{{model.name}} //=> Joe
I think this might be a thing about explicitness but I'm not 100% sure - you can also have data sent to the template on a property other than model so it might be about allowing that to be more easily understood - model is a poor property name IMO anyway
You could use the with helper if the syntax is too verbose for you:
{{#with story}}
<div class="intro">{{{intro}}}</div>
<div class="body">{{{body}}}</div>
{{/with}}

Ember customize id attribute of component

Hi is there a way to customize the id of a component (i know it can be done for views ...but views have be deprecated since ember 1.13):
E.g. the following worked for the view:
export default Ember.View.extend({
classNames: ['music-js', 'vjs-default-skin', 'center-x','center-block'],
attributeBindings: ['id'],
id: 'musicOne',
However when I attempt to use id binding for the component i get the exception in the console logs:
export default Ember.Component.extend({
classNames: ['music-js', 'vjs-default-skin', 'center-x','center-block'],
attributeBindings: ['id'],
id: 'musicOne',
Uncaught TypeError: The element or ID supplied is not valid.
2 ways:
In the component itself:
export default Ember.Component.extend({
elementId: 'the-id'
});
Or specifying it in the component call itself:
{{my-component id="the-id"}}
I think the reason for NOT being able to do this is that the component is automatically assigned an ID by the Ember framework itself. You can see that if you inspect the HTML when you run your app:
<div id="ember428" class="ember-view">
But you can get a handle on that auto-generated ID and pass that to the JQuery plugin, instead of creating your own ID as per Mikko's answer.
See this to learn how to do that.
I think this is the preferred way, since components should be 'isolated' from external dependencies. By having to pass in the ID from the template defeats that (as per Mikko's suggestion) - since any consumer of a component would have to know what ID to pass in for the component to work.
However, Mikko has now edited his answer, so setting your own ID inside the component, also satisfies the 'isolation' requirement (ie. using elementID: 'the-id')

Why is that using itemController renders a collection of empty items?

I'm currently learning Ember while following the todomvc tutorial with ember-cli: http://thetechcofounder.com/getting-started-with-ember-js-using-ember-cli/
I'm in the section where in order to edit a todo, it's needed to add the editTodo action in the TodoController. So far so good, but it also says to use itemController on the each handlebars helper to tell each todo to use a specific controller
.
The thing is that when I add itemController to each in the template (using Emblem.js: each itemController='todo'), the template no longer renders the title of each item on the collection, it only renders them blank:
I cannot understand why this happens.
Template extract
section#main
ul#todo-list
each
li class={isCompleted:completed}
if isEditing
input.edit
else
= input class='toggle' type='checkbox' checked=isCompleted
label{action 'editTodo' on='doubleClick'}= title
button.destroy
input#toggle-all type='checkbox'
Controller extract
`import Ember from 'ember'`
TodoController = Ember.Controller.extend
actions:
editTodo: ->
#set 'isEditing', true
`export default TodoController`
An item controller must be an Ember.ObjectController to successfully render each item and its associated data. ObjectControllers are used to decorate individual items within an ArrayController. Use the itemController property in the 'TodosListController' ArrayController to declare the item controller:
itemController: 'todo',
Then, when creating the 'todo' item controller class definition as suggested in the referenced tutorial, observe that the Ember CLI 'generate controller' command will create a standard Ember Controller. Standard Controllers and ArrayControllers represent multiple items (like the 'TodosController' or 'TodosListController'). Thus, the TodoController should extend Ember.ObjectController to represent singular items:
`import Ember from 'ember'`
TodoController = Ember.ObjectController.extend
actions:
editTodo: ->
#set 'isEditing', true
`export default TodoController`
A standard Ember.Controller, as posted with the question, fails to display each of the individual todos properly, when passed via the 'each' helper, because the model for the standard controller is referencing a filtered set of all records of type 'todo', instead of a particular, single todo record.
I’ve created a JS Bin to illustrate - just toggle between using Ember.Controller and using Ember.ObjectController for the 'TodoController', to see the standard controller fail.
Also, not the cause of the issue, but just in case it was overlooked, the ‘isEditing:editing’ is missing from the list-item class attribute declaration:
section#main
ul#todo-list
each itemController='todo'
li class={isCompleted:completed, isEditing:editing} // <-- here
if ...

Why is Firebase data not displaying properly in my Ember CLI generated output?

I've successfully setup Ember CLI and Firebase and I'm attempting to bring some basic data into my templates. My 'title' and 'subtitle' data are apparent in the Ember Inspector, as well as my Firebase project dashboard. However, {{foo.title}} and {{foo.subtitle}} are coming back empty and undefined in the browser. Why is that? Here's my code:
application.js (adapter)
import DS from 'ember-data';
export default DS.FirebaseAdapter.extend({
firebase: new window.Firebase('https://<firebase-database-name>.firebaseio.com/')
});
foo.js (model)
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
subtitle: DS.attr('string')
});
index.js (controller)
import Ember from 'ember';
export default Ember.Controller.extend({
model: function() {
var titles = this.store.createRecord('foo', {
title: 'Title',
subtitle: 'Subtitle'
});
titles.save();
}
});
index.js (route)
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('foo');
}
});
application.hbs (template)
<h2 id='title'>{{foo.title}}</h2>
{{outlet}}
index.hbs (template)
<h1>{{foo.title}}</h1>
<h3>{{foo.subtitle}}</h3>
The title and subtitle fail to display in the templates.
The Ember Inspector View Tree tab shows 'index' with 'DS.RecordArray:ember368' for the model.
The Ember Inspector Data tab shows Model Type of 'foo' with # Records of 1. When I click on that record, it displays the Firebase ID, title, and subtitle values. When I inspect my Firebase data url, I see the following structure:
firebase-database-name
|— foos
|— JU1Ay8emCNNZBeqYoda
|— subtitle: "Subtitle"
|— title: "Title"
Seems like everything is correct, but the templates do not display the data values. Thanks for any help.
The answer to this question centers on properly retrieving and exposing Ember Data, and not so much to do with Firebase or Ember CLI. There are multiple issues with the code above…
The foo.js code represents a simple model, and is written correctly.
The index.js route is implemented correctly. It is retrieving and returning the ‘foo’ model from the Ember Data store as an array, which, via EmberFire and the Firebase adapter, is ultimately being pulled from the Firebase database. However, this is part 1 of 3 problems. If you want this data displayed once across the application, dispense with the index.js route, and just define an application.js route, like this:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('foo');
}
}
The index.js controller has a number of issues, and is part 2 of 3 problems. Firstly, controllers do not have a ‘model’ method, they only have a ‘model’ property (Ember Routes are the ones that employ a ‘model’ method, and can also set the ‘model’ property of a controller via a Route’s ‘setupController’ method). Secondly, instead of Ember.Controller, it needs to extend Ember.ObjectController for a singular data instance, or, Ember.ArrayController for an array of data, which is the controller needed here, since ‘this.store.findAll(“foo”)’ in the index.js route is going to return an array of objects. Controllers are not used to save or retrieve data from a server, but they can be used to decorate a model. Given that the route is returning the model, the controller, in this simple data exercise, is not even necessary.
The application.hbs handlebars template is part 3 of 3 problems. It is not setup to properly display the model that is being provided to it via the route. It’s necessary to employ the {{#each}} helper, to loop over the data array that is being returned via the route’s model method. Try this:
{{!-- looping over the 'foo' model returned via the route --}}
{{#each foo in model}}
<h2>Application Title = <span style="color: blue;">{{foo.title}}</span></h2>
<h4>Application Tagline = <span style="color: blue;">{{foo.tagline}}</span></h4>
{{/each}}
{{outlet}}
The index.hbs handlebars template is not necessary. The application.hbs template is sufficient to display the data of interest.
This is a very basic exercise, but illustrates fundamental aspects of using Ember Data properly.

How do I add classNames to the first element of the page without using a view?

I want to add a wrapper class to the first div element in my page. I used to do this with a view. So, it seems that Ember 2.0 won't support Views anymore. So how can I do that now?
view/application.js:
import Ember from 'ember';
export default Ember.View.extend({
classNames: ['wrapper'],
});
Resulting in the following page:
<body class="ember-application">
<div id="ember573" class="ember-view wrapper">
the rest of my page in this div
</div>
</body>
How is this done now that views are deprecated?
I used css to solve this problem:
body > .ember-view {
padding-left: 240px; //styles for container goes here
}
I don't have a neat solution, but subclassing Ember.Component from inside applications/view.js works.
https://ember-twiddle.com/b15411266f996191605c
Like the others said, the only way to add a class using Ember 2.0 is to use a component on your page. The component has the same properties that the view had. Your page will have a component-only call in the template, like the following:
your-page.hbs
{{your-page-component}}
If you really don't want to have a component on your page, my advice to you would be to add manually a class name in your template:
your-page.hbs
<div class="your-page">
{{outlet}}
</div>
Views are deprecated in ember 2.0. The way to do things from now on is using component and route. You can specify which class name is applied to your component by doing:
export default Ember.Component.extend({
/* Wrap your component in primary class*/
classNames: ['primary'],
/*defined class binding*/
classNameBindings: ['isUrgent'],
isUrgent: true
});
All information regarding on how to customize your component can be found in the ember documentation(click here to find out more)
You're not supposed to use Views now since they're deprecated. Use components instead, example:
import Ember from 'ember';
export default Ember.Component.extend({
classNameBindings: ['functionName'],
functionName: Ember.computed(function() {
// function logic
})
});