Component doesn't use template - ember.js

I want to extend Ember's textarea component.
Therefore I created a file drop-files-textarea.js in app/components with this content:
import Ember from 'ember';
export default Ember.TextArea.extend({
// here comes the new behaviour
})
Now I'd like to add something to it's template. Therefore I created a file called drop-files-textarea.js in app/templates/components with this content:
{{yield}}
<p>added text</p>
This template is never used though.
The Ember Inspector shows me that it uses the inline-template.
What am I doing wrong?

The template is used, but you won't see anything since the TextArea component uses tagName: 'textarea' to wrap the component in a textarea html element, so you get:
<textarea>
<p>added text</p>
aaaa
</textarea>
You may want to create a new component using the textarea component inside or use the value property to set the content of the textarea depending on your use case.
You could also overwrite the tagName, but then you don't get a text area...
export default Ember.TextArea.extend({
value: 'Content of the text area'
})

Related

Ember js - convert handlebar component into a string

I am using Ember CLI 1.13.8 and have a file info.hbs:
Your name is {{name}}
I want to convert this handlebar into a string like:
"<div>Your name is xxx</div>"
How can I achieve this?
There's no easy way to do this, but I can think of at least one way. Render your HTML to a hidden component, then grab the HTML from the DOM directly.
export default Ember.Component.extend({
style: 'display:none;',
didRender() {
// Do whatever you want with the HTML
const htmlString = this.$().html();
}
});
You can place this component anywhere in your app. Depending on your use case you might want to combine this component with the component that will render your infoview, or just place this in the application template and have it update some state when it changes.

ember application template classname

I'm having a similar problem to this one:
Setting tagName on application template in ember js
While I agree that falling back to a legacy view addon can't be the way to go, here too my bootstrap-based CSS is broken by the enclosing div (the height being not set, to be precise).
Now a different way to achieve what I need is to set the enclosing div's classNames property (if it exists), like it can be done with a component:
export default Ember.Component.extend({
classNames: ['container']
});
Thus I could apply height:100%, and everything would be fine.
Update:
The problem is not the styling of the enclosing div of a component, but the way the main application template behaves. Let me clarify:
application.hbs:
{{outlet}}
Therein is rendered a route's template, e.g. map.hbs:
{{#tab-navigation-container}}
{{top-nav}}
{{tab-contentpane model=model}}
{{tab-navigation map=true}}
{{/tab-navigation-container}}
Now, components/tab-navigation-container.js transforms the enclosing div to include the container CSS class:
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['container']
});
However, the rendered HTML looks like this:
So, seemingly application.hbs puts another div around the component, and I'm looking for a way to either
remove it (which can only be achieved by a legacy view addon, as explained in the link above) or
apply a className to it.
Can it be done? Thanks!
Okay, this is more of an ugly hack than an actual solution, but for the moment it does the trick. I just fell back to ordinary jQuery DOM manipulation while overwriting the component's didInsertElement event:
export default Ember.Component.extend({
setupFunc: function () {
$('#tab-navigation-container').unwrap();
}.on('didInsertElement')
});
where tab-navigation-container is the component's ID.
You should set tagName and classNames to be your outer most element--this will keep consistent styling. For example, say originally you had:
<section class="container col-md-6">
<div class="col-sm-12 test">
<p>some content...</p>
...
</div>
</section>
You would create your component like this:
export default Ember.Component.extend({
tagName: 'section',
classNames: ['container', 'col-md-6']
});
Then your template can exclude the outer section wrapper
<div class="col-sm-12 test">
<p>some content...</p>
...
</div>
There's really no reason why your CSS should be broken by using components. You can set all the same classes and tags that you were using before and CSS should render just the same.
Let me know if I misunderstood your question.
In Ember 2.7 and below, you can control the top-level tag (even not rendering it), and its CSS classes by modifying your Ember Application as follows:
// app/app.js
App = Ember.Application.extend({
ApplicationView: Ember.Component.extend({
classNames: ['my-custom-classname'],
// Or to omit the tag entirely:
tagName: '',
}),
// ...
});
As seen in this discussion.
This does not require any hacks or a legacy plugin.

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')

Ember JS/Handlebars view helper

Currently, if we define our view as {{#view App.myView}}, ember/handlebars will wrap the view element inside a <div id="ember-1234" class='ember-view'>.
Is there a way to stop this?
You probably want to set tagName as ''.
App.MyView = Em.View.extend({
tagName: ''
});
At least it stops wrapping inner contents.
If you want to customize view element's id, you can use:
{{#view App.myView id="my-id"}}
I usually think my views as wrapper. For example, if the initial given html code is :
<div class="item"><p>my stuff></p></div>
Then I create a view with a tagName property as "div" (which is default), and classNames property as "item". This will render, with proper handlebars template :
{#view App.myView}
<p>my stuff></p>
{/view}
-> render as
<div id="ember-1234" class="ember-view item">
<p>my stuff></p>
</div>
Then if you need to have your proper ID on this div, you could define the "elementId" property on your view class (before create()). (#see source code)
I assume you are talking about the 'ember-view' class which is not customizable (element type being customizable thanks to the tagName attribute...).
Actually, Ember later uses this class to register (once!) an event listener on the document in order to dispatch events to the JS view.
I don't mind it would be that simpler to avoid using this class. There would have to find another way to select all ember's controlled element, but I have no idea how.
See source, # line 117.
If I understand you correctly you want to achieve something like jQuery's replaceWith? You can use this in Ember.js when my Pull Request gets merged: https://github.com/emberjs/ember.js/pull/574.
Also have a look at Create Ember View from a jQuery object

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
})
});