This Ember template code...
<div class="detail bedrooms">
<span>Number of bedrooms:</span> {{rental.bedrooms}}
</div>
<div class="detail temperature">
<span>Current Temperature:</span> {{city-temperature location=rental.city}}
</div>
...results in this rendering...
How could one get the "25C" text to render on the same line as "Current Temperature" in the same way that "San Francisco" is on the same line as "Location"?
I have tried getting the city-temperature component to return only text, but (secondary question here) is it even possible for a component to return only text if the text is from a remote ajax request since the promise seems to need a DOM element to append to?
This Ember app is available here on GitHub. It's a modified version of the official Ember.js tutorial app with this "Current Temperature" detail added.
The problem is that; city-temperature is a component; and by default ember components is assigned div as their tags. Due to this; the content of city-temperature starts at a new line.
What can you do? Play with css and make sure div tag of city-temperature does not start at a new line; but instead floating right within the owner div. The second option is making city-temperature component tagless; so that it does not start at a new line. To achieve that; you can just declare:
tagName: ''
within city-temperature.js. You can see the following twiddle to see the second option I mentioned.
After reading your comments; I have forked your repository and made minor modifications to achieve what you want. You can check my repository and my corresponding commit to see what I changed.
Basically; I really did not like the idea that weather service is returning a DOM element. I have changed it to return an instance of ember promise (I mean Ember.RSVP.Promise). Within city-temperature.js I just set a retrieved weather value from weather service and set it to the component instead of making DOM modification. Finally; I modified city-temperature.hbs to render weatherValue and added a simple css item in order to prevent weather-container div to insert a new line break.
I am not sure; whether you will like my solution or not; but I guess you will retrieve the visual appearance you want. You can always rely on promises for async tasks; you do not need to create DOM elements and pass them around to components and append them to somewhere within DOM tree of the corresponding component. I believe one of the reasons we are making use of a framework like Ember is to prevent such DOM modifications. Best regards.
An ember component adds a div by default. If you don't want to add this div tag, you need to set tagName to an empty string.
That's called tagless component.
Further, for your case, you can give a tagName='span' so you will not need a span in your template.
export default Ember.Component.extend({
tagName: 'span',
classNames: ['weather-container'],
weather: Ember.inject.service(),
//rest of your code...
});
Related
How to understand an ember application code .
I want to backtrack where a variable is defined from web page to component.
example :
in web page Title : "Wonder boy"
in template it is mentioned as
{{title-works field as |f|}}
title = field.label
{{#titel-works}}
but in the component for this template i am not able to find the varaible field nor field.label . can you please provide me any resource to understand how to backtrack a ember application from web front to variable . thanks .
First of all, your template looks a bit wrong. First the variable f is never used, next title = field.label is not hbs syntax and should literally print the string "title = field.label". Is it maybe emblem?
Now I just assume you actually use a variable as in {{field.label}}.
If you dont have the variable in the component it is passed down to it when the component is called.
So either by {{your-component field=something}} (old syntax) or <YourComponent #field={{something}} /> (newer syntax).
This is indeed not very clear. That is the reason why {{field}} (and {{field.something}}) is deprecated in favor of either {{this.field}} (or {{this.field.something}}) when the data comes from the component.js (or controller.js in case of a route template) or {{#field}} (and {{#field.something}}) when it is passed down to the component, so it is always clear from where it comes.
Your best resource when debugging is the ember-inspector. It can show you the component tree, so you know exactly from where your component is called and where to look.
I have navbar component which I have placed in an application.hbs so that it should be visible always.But I want to change the title of the navbar with each page I visit ( say I am on index page it should say "Home" , if I am on profile page it should say profile,etc).Right now what is happening is navbar title always remains "Home" for all the page.This is happening because the navbar gets rendered onlu during the time it loads the page in browser and after that it doesn't change according to page.
application.hbs
{{top-navbar dp_url=model.profile.dp_url first_name=model.profile.first_name title=title}}
{{outlet}}
Here the I am computing the value of title depending upon which page the user is.
application.js(controller)
if (currentPage === "" || currentPage === "#"){
currentState.set('title',"Home")
}
else if(currentPage === "Userprofile"){
console.log('myStudio');
currentState.set('title',"UserProfile");
}
In here the currentpage has the current url of app and I am comparing it and deciding the value of title for navbar.
But the top-navbar title value gets calculated only for the first time when user load the app in browser and not when I move ffrom one route to another.
I have also tried the Ember.Evented but not able to solve it.
I don't know what Ember.js and Ember-data version are you using, currentState is deprecated since 2.1, anyway looks like you're using a private method intended for Ember internals and not meant to be used in an application.
A possible (but maybe unnecessary complicated) way to accomplish what you want is:
Create a model with the information you want to mutate in the navbar (e.g. navbar-data).
In the route where the navbar is rendered, create and return a record for it using a fixed numeric ID (e.g. store.createRecord('navbar-data', { id: 1, title: "index" })).
Pass the created record to the component (instead of just a string).
Whenever you want to change, peek the record with store.peekRecord('navbar-data', 1) and change the value you want to change in the navbar.
Of course, the record you use for that must not be saved with record.save().
I have a ember component that is accessing a database and returning the results in a datatable type UI component. I would like to be able to use "N/A" when the result of the component is null or nothing.
For example, I have:
{{each bar in foobars}}
<td class="classyTD">
{{getBars bar=bar}}
</td>
{{/each}}
This works great when I have data, but returns nothing when I don't have data. The designers would prefer an "N/A". Modifying the database isn't an option and while modifying the component getBars is an option, it will be extremely painful.
Is there a method/way to handle this after the execution of the component? If not, or if it's a terrible idea - I'll suffer through changing the component, I trust the community's opinion.
You really should do this inside the component template. You can give the N/A string as a parameter, if that's of any help: http://emberjs.jsbin.com/lemabekuwi/2/edit?html,css,js,output
Or you could change the component that it indicates emptiness through a class and use some css magic: http://emberjs.jsbin.com/duqazahegi/1/edit?html,css,js,output
If you want to limit logic in the handlebars you can have the following in the component js file:
({
setBar: (function() {
if (!this.get('bar')) {
return this.set('bar', 'N/A');
}
}).observes('bar')
});
For my project, I have a requirement for directives to be defined that do not modify the DOM, and also do not leave artifacts of their existence in the DOM. I seem to be unable to make this work with AngularJS.
Consider these examples:
<div empty-arg="some-param"></div>
<div null-arg="another-param"></div>
With associated directives defined as follows:
var module = angular.module( 'component', [] );
module.directive('emptyArg', function() {
template: '',
replace: true,
scope: false,
link: function() { // ... }
};
module.directive('nullArg', function() {
template: null,
replace: true,
scope: false,
link: function() { // .... }
};
After compilation, I want the resulting DOM elements to look like this:
<div></div>
<div></div>
But the absence of a template seems to cause AngularJS to ignore the replace request, leaving the resulting DOM elements looking like this:
<div empty-arg="some-param"></div>
<div null-arg="another-param"></div>
How can I force AngularJS to get rid of these attributes in the post-compile DOM?
A jsFiddle demonstrating this can be found here:
http://jsfiddle.net/vankirkc/ezN3M/34/
Update:
It is possible to delete the created attributes after they are created, but what I am really looking for is some way to leverage the template definition parameter to intercept the creation of the DOM element such that it doesn't copy this directive across. It appears this isn't possible in version 1.0.3.
Actually "empty-arg" and "null-arg" are just normal attributes of DOM element, AngularJS is using them to mark which directives to apply at element.
So it would be actually bad, if one directive will remove attributes from DOM element. For example - it is possible to write another directive that will use this attributes to modify its behaviour: in different AngularJS libraries you can see, that controls use ngModel attribute to get expression on which element is been bound.
And also as those attributes are already present at DOM tree, deleting them will cause DOM tree modification and can imply performance issue.
If still you actually whant to delete those attributes, you can try to modify second argument of linking function:
attrs.$set('empty',undefined);
But generally I would not recommend to do so: you can save some memory (but I am not sure that it would be saved - I think it should be benchmarked), but you'll get bigger loading time as DOM tree would be modified.
But anyway here is Fiddle to demonstrate that it is possible.
If you want to remove all attributes, you can do it in the compile function:
for(var i=0; i < tElement[0].attributes.length; i++){
tElement.removeAttr(tElement[0].attributes[i].name)
};
Fiddle.
Update: as #Josh pointed out in a comment, removing the attributes will essentially make this a run-once-only directive, and none of the attributes will be available in the link function, making this answer a non-answer/non-solution.
I am trying to use ember to show a dynamic list of found content. The problem is that when I try to put handlebars in html attributes, everything breaks.
RegApp.PatronsFound = Ember.CollectionView.create
tagName: 'table'
content: []
itemViewClass: Ember.View.extend
template: Ember.Handlebars.compile("<td><button onclick='alert({{content.id}})'>{{content.name}}</button>")
RegApp.PatronsFound.appendTo('body')
When it is fed a piece of content with the ID of 3 and the name FOO, I want this html to be generated:
<button onclick="alert(3)">FOO</button>
Instead, I get this:
<button onclick="alert(<script id=" metamorph-4-start'="" type="text/x-placeholder">3<script id="metamorph-4-end" type="text/x-placeholder"></script>)'>FOO</button>
You can use
{{unbound content.id}}
to arbitrarily insert values into your templates. Normally, such values are wrapped in metamorph tags which allow the displayed value to be bound to the backing value, and updated whenever the backing value changes. This only works if the output is regular HTML, not, in this case, spanning event handlers and embedded JS. {{unbound}} inserts the value at that property path once, without metamorph tags, and without being updated if that value changes in the future.