I have a view with the following:
App.MyView = Ember.View.extend({
isSet: false,
layoutName: 'myview',
click: function() {
this.set('isSet', !this.get('isSet'));
}
};
And the template for it:
<i {{bind-attr class=":fa isSet:fa-check"}}></i> Toggle
The click event is working fine, and updates isSet (I can see that in ember inspector), but the bound class does not get added. Is there something wrong in my logic?
Use view.isSet instead of isSet in your template.
<i {{bind-attr class=":fa view.isSet:fa-check"}}></i> Toggle
Another possible solution, not to the OP's problem but to one with a similar title.
When using bind-attr to bind property changes and element class, it is important to include also static class mapping inside the bind-attr helper and not in a separate, static, class attribute.
This will not always work:
<div class="round" {{bind-attr class="highlighted:hl"}}>Inner text</div>
The correct way is:
<div {{bind-attr class=":round highlighted:hl"}}>Inner text</div>
If you are using above ember 1.11
then use the below tag
Reference :
http://www.hutchinson.io/bind-attr-is-dead/
Related
Demo
Demo fixed accordingly to accepted answer
Consider a component, let's call it <simple-dialog>, with this template:
<button type="button" (click)="visible = !visible">TOGGLE</button>
<div *ngIf="visible">
<ng-content select="[main]"></ng-content>
</div>
I omit the component TypeScript definition cause it's basically the same as the one generated by ng-cli.
Then I use it like this:
<simple-dialog>
<div main>
<app-form></app-form>
</div>
</simple-dialog>
When i first click the button the child component is rendered; if I click the button again the child component is removed from the DOM.
The problem is that, at this point, app-form's ngOnDestroy is not called.
I'm new to angular, so I am not sure whether my expectation is wrong.
What you are trying to achieve is called conditional content projection.
In your case, by using ng-content, the components are instantiated by the outer component, unconditionally - the inner component just decides not to display it.
If you want conditional instantiation, you should pass a template instead:
<simple-dialog>
<ng-template>
<div main>
<app-form></app-form>
</div>
</ng-template>
</simple-dialog>
and use an #ContentChild annotated property to access
the template from the content within the SimpleDialogComponent:
#ContentChild(TemplateRef, { static: false })
content!: TemplateRef<unknown>;
which can then be rendered in the template as
<div *ngIf="visible">
<ng-container [ngTemplateOutlet]="content"></ng-container>
</div>
You can also read about this here:
https://angular.io/guide/content-projection#conditional-content-projection
I have an ember application which works fine. But user's interaction does some DOM insertion like below...
$(.test).append(<a {{action "getData"}}>Get Data</a>);
The problem is that Ember seems do not recognize that an action "getData" has been added to the DOM. Nothing is happening when I click the element. Any thoughts on this?
Another way I am trying to do is:
//create the element
$(.test).append(<a id="idnum">Get Data</a>);
//make click listener
$('#idnum').click(function(){
console.log("get data");
}
my question is where should i place the code inside the component so the it can listen on the click event. Thanks.
You should do it in Ember way. Try handlebars {{#if}} helper to render an element dynamically.
{{#if canGetData}}
<a {{action "getData"}}>Get Data</a>
{{/if}}
Here you can set the value of the canGetData to true in the controller based on the users action.
The first example can't work because ember does not analythe the Handlebars elements in the DOM, but rather parses your Handlebars template with HTMLBars, which is a full HTML parser, and then renders it manually by inserting elements, not text into the DOM.
However the second example is the way to go if you have to rely on external code that does manual DOM manipulation. And it does work. Checkout this twiddle.
This does work:
this.$('.target').append('<a id="idnum">Get Data</a>');
this.$('#idnum').on('click', () => {
alert('clicked');
});
Just make sure that the DOM is ready. So do it in the didInsertElement hook or after the user clicked a button or so.
Like Lux suggested avoid DOM manipulation. I prefer the following approach,
if it is dynamic then you can consider wrapping DOM element as a new component and use component helper.
find sample twiddle
In application.js
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
linksArray:[ Ember.Object.create({value:'Text to display',routename:'home'}),
Ember.Object.create({value:'Text to display2',routename:'home'})],
actions:{
addItem(){
this.get('linksArray').pushObject(Ember.Object.create({value:'AddedDynamically',routename:'home'}));
}
}
});
in Application.hbs
<h1>Welcome to {{appName}}</h1>
<br>
{{#each linksArray as |item|}}
{{component 'link-to' item.value item.route }}
{{/each}}
<button {{action 'addItem'}}>Add Item</button>
<br>
{{outlet}}
<br>
<br>
I have a component that is wrapping content defined by another template. I want an action on the template to trigger a method in my surrounding component. Is this possible?
Here is what I have for my template. Note this is shortened for brevity.
{{#drop-down}}
<div class="menu-selector clickable" {{action "toggleDropdown"}}>
</div>
{{/drop-down}}
This is my component:
DropDownComponent = Ember.Component.extend
showDropdown: false
actions:
toggleDropdown: ->
#toggleProperty 'showDropdown'
`export default DropDownComponent`
I can verify that everything else in my component is working. If I put the action in my component that loads this template, it works fine. But that's not where I want it.
So you would like to send an action to particular components. Take a notice that
A component is a custom HTML tag whose behavior you implement using JavaScript and whose appearance you describe using Handlebars templates. They allow you to create reusable controls that can simplify your application's templates.
and
An Ember.Component is a view that is completely isolated.
You are probably using wrong tool here. You should use instead custom view.
App.DropdownView = Ember.View.extend
showDropdown: false
elemendId: 'dropdown'
actions:
toggleDropdown: ->
#toggleProperty 'showDropdown'
return;
{{#view 'dropdown'}}
<div>
<div class="menu-selector clickable" {{action "toggleDropdown"}}>
</div>
{{/view}}
Then you can send an action to view by
Ember.View.views.dropdown.send('toggleDropdown');
Demo: http://jsbin.com/zoqiluluco/1/
I have following issue here:
<ul class="aClass">
{{#if something}}
<li>{{#link-to "blub" bind-attr data-testid=aID}}{{loc "blub"}}{{/link-to}}</li>
{{/if}}
</ul>
so i want to have an element(the link-to is rendered to ...) in the resulting element with the id aId. But the element does not contain the wanted id in the rendered HTML. something like this:
...
any ideas?
In Ember, bind-attr shouldn't be used inside of your link-to help as that should only be used inside of html elements:
<a {{bind-attr href=myLink}}>My Link</a>
Inside of Handlebars helpers, you just define the property directly.
{{#link-to "blub" data-testID="aID"}}{{loc "blub"}}{{/link-to}}
The attribute is not rendered into the HTML if the quotes are missing.
But you also need to reopen the LinkView:
Ember.LinkView.reopen({
attributeBindings: ['data-testID']
});
See similar question here.
And the Ember docs here.
Try using quotes:
{{#link-to "blub" bind-attr data-testid="aID"}}{{loc "blub"}}{{/link-to}}
A lack of quotes will cause Ember to try a property lookup on the current view context, instead of just spitting out a string as you'd like it to.
For some reasons, I can only add javascript after Ember application is created (i.e. all UI inited).
The HTML looks like this:
<div id="ember21643" class="ember-view form_field ticket_type_id has-ticket-type-field">
<label for="">
<script id="metamorph-249-start" type="text/x-placeholder"></script>
Type
<script id="metamorph-249-end" type="text/x-placeholder"></script>
</label>
<div id="zd_mn_385" class="zd-selectmenu zd-selectmenu-root zd-state-default">
<button id="zd_mn_386" class="zd-selectmenu-base" role="button" tabindex="0" style="width: 131px; "><span class="zd-selectmenu-base-arrow zd-icon-triangle-1-s"></span><span id="zd_mn_387" class="zd-selectmenu-base-content">-</span></button>
</div>
</div>
It's easy to use jQuery to target the to do direct DOM modification but I worry that it will break the Ember application.
Is there a proper way to change this view, for example:
append/prepend a text to the div container
change the text to something else instead of "Type" as in the above example.
Using DOM inspection, this view looks like it can be accessed from:
Ember.View.views.ember21643
And
Ember.View.views.ember21643._childViews[0]
is pointing to "label". So I set
Ember.View.views.ember21643._childViews[0]._lastNormalizedValue = "ABC"
but it's still showing "Type" on the screen so probably this is not the way to do.
Please help. Thanks alot. (I'm new to Ember).
I'm not sure if i'm missing your point but, if I wanted to change the text in an ember view, I think I would use the Ember bindings.
template
<div id="someView" type="text/x-handlebars">
This sentence has a dynamic {{ end }}
</div>
view
App.someView = Ember.View.extend({
end : 'conclusion',
templateName: 'someVIew' //not really necessary with new router to be explicit
})
view with binding
App.someView = Ember.View.extend({
endBinding : 'contoller.end',
templateName: 'someVIew' //not really necessary with new router to be explicit
})
Does any of that help? :)