Reputation: 41236
Ok, so let me preface this by saying I'm completely new to Ember. I'm having an interesting time just trying to get a basic binding to work. Here's my relevant code:
App.js
var App = Ember.Application.create({
rootElement: '#emberApp'
});
And routes.js:
App.Router.map(function () {
});
App.IndexRoute = Ember.Route.extend({
model: function () {
return { Foo: 3 };
}
});
And then here is my HTML document:
<div id="emberApp"></div>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/handlebars.js"></script>
<script src="~/Scripts/ember-1.4.0.js"></script>
<script src="~/Scripts/EmberApp.js"></script>
<script src="~/Scripts/Routes.js"></script>
<script type="text/x-handlebars" data-template-name="index">
<div>The current foo value: {{Foo}}</div>
{{input valueBinding=Foo}}
</script>
The intended result is that when I type in the input field created, the value that is bound in the template changes at the same time. It should be fairly simple right? I have to be missing something.
The template correctly renders The current foo value: 3
, and it renders a text field. However, typing anything into this field does nothing to the above binding. I have tried marking it with a valueBinding
tag, as well as switching to Ember.TextField
instead of a input
helper. I've also tried making a custom Ember.Object.extend
class and returning that as the model for the index route.
What am I missing in order to bind the text box value to the {{Foo}}
value in the template?
EDIT - Ok, I've figured out it's because of the capitalization of the variable: foo
works, but not Foo
. Why is this?
I'm expecting to receive JSON results similar to this:
{
RemoteUserId: 0,
UserPhotoUrl: '....',
RemoteUserName: 'Bob',
}
I'm assuming this means I need to 'hide' these values by making controller wrappers for each element? ie:
remoteUserId: function() {
return this.get('RemoteUserId');
}.property()
Upvotes: 0
Views: 641
Reputation: 18240
Its because in Ember properties should start with a lowercase letter! Uppercase letters are globals.
so u could simple convert your JSON bevore import it into ember:
var decapitalize = function(source) {
var result = {};
for(var prop in source) {
result[prop.substr(0,1).toLowerCase() + prop.substr(1)] = source[prop];
}
return result;
};
Upvotes: 0
Reputation: 3313
I'm afraid you've been bitten by one of Embers naming conventions which is normally awesome as it usually means things just work, but occasionally will bite you if you're not aware of it.
Ember expects that Classes or Namespaces are capitalized and that instances are lowercase. When Ember sees the Foo
property used in a binding it assumes it's a namespace and will then look for a global variable called Foo
instead of a controller property.
When you use {{Foo}}
in a template the behavior is slightly different as Ember will first check the current context (the controller) to see if the property exists there. If it does it uses that value, otherwise it will assume it's a namespace and look for it globally. Bindings don't work like templates due to performance concerns as you don't want to have to check two locations for a value in a binding that could be updated very frequently (like a textbox being typed in).
This is why you can use Foo
in the template and it works:
<script type="text/x-handlebars" data-template-name="index">
<!-- This works! -->
<div>The current foo value: {{Foo}}</div>
</script>
But when you try to use Foo
as part of a binding it won't work:
<script type="text/x-handlebars" data-template-name="index">
<!-- This doesn't work as Ember thinks Foo is global (i.e., a namespace) -->
{{input valueBinding=Foo}}
</script>
Your best bet is to just follow ember conventions and make sure all your property names start with a lowercase character. However, if you want to continue using properties in your controllers that start with a capital character then you will need to explicitly tell Ember that the property is from the controller and is not global when you try to use it in a binding:
<script type="text/x-handlebars" data-template-name="index">
<!-- Tell Ember Foo is in the controller which is what we want-->
{{input valueBinding=controller.Foo}}
</script>
Here is a Fiddle demonstrating everything written above:
Upvotes: 2