I'm learning emberjs and I've done a pretty simple example. The HTML template is:
<script type="text/x-handlebars">
Hello <b>{{App.appOwner}}</b>
</script>
And then the javascript is:
App = Ember.Application.create({
appOwner : 'Erik'
});
App.appOwner = 'Tom';
Which does pretty much what you expect. The emberjs.com documentation says templates are auto-updating -- so I added this:
$(document).click(function() {
console.log('HERE!');
App.appOwner = 'Alphonse';
});
Which quite unexpectedly failed. I had added the console.log just to make sure the click handler was being called, which it was. Why doesn't it update?
You need to use .set() mutator method, because javascript doesn't have facilities to intercept the direct properties changes:
App.set('appOwner', 'Alphonse');
Related
I'm in a shop where we can't use ember-cli (this saddens me, but it is what it is), and we'd like to use ember-data along side our app. The documentation gets us started, but I can't seem to initialize the store correctly (I think).
Here's what we have:
<script src="../ember/ember.debug.js"></script>
<script src="../ember-data/ember-data.js"></script>
<script>
(function(){
'use strict';
window.File = window.File || DS.Model.extend({
id: DS.attr()
});
window.store = window.store || DS.Store.extend({
'file': window.File});
})();
window.store.findRecrod('file', 1); // findRecord Doesn't exist
})();
</script>
The classes get defined correctly, but the method findRecord doesn't exist. What am I doing wrong?
Am I initializing the store incorrectly, or do I need to register the Model a different way, or is it something else?
We'd like to use the default JSONAPI adapter, FWIW.
You have to .create the instance. However just because you dont use ember-cli doesnt mean you cant use the DI-Container.
To speak about ember-cli, are you sure you wont find a way to combine it with your workflow? I strongly recommend you to use it, especially if you'r not very expecienced with ember.
I am having a little trouble hiding an element. I am attempting to hide this element using an AngularJS service. My code is as follows:
app.service('testService', function(){
var testElement = $("#testElement");
this.hideElement = function(){
testElement.hide();
}
});
The code above does not actually hide the element, but the following code does:
app.service('testService', function(){
this.hideElement = function(){
var testElement = $("#testElement");
testElement.hide();
}
});
However, I have multiple functions that use the testElement and I would hate to have to keep declaring it in all the functions that need testElement within the service. Am I doing something wrong here?
Am I doing something wrong here?
Yes. In fact your very first step was wrong. I mean having service that makes some DOM manipulations, in your case hiding HTML node. Services are data manipulation layer (retrieve, transform, save, post, etc.) but never presentation one, it should not care about View. Services are reusable piece of application code, meaning that it is supposed to be injected in different places of the app to provide a bridge to data sources, it should not make any view transformations, it's just not what they are for.
You should use directive for this with controller as mediator to decide when and what to hide and show. Most likely it will be enough to use build-in ngShow/ngHide directives with some boolean flags set in controller.
for html manipulation better to use angular controllers or inbuilt directives. services are never recommended.
If you really want to cache something, use simple JS Constants or html5 localstorage if you cache session wise use sessionstorage, they are really helpfull. or in angular $rootscope variables are also global.
Yes. What actually happened when you assign 'testElement' outside the hide method was 'testElement' will be assigned with undefined value.Since injection are created before the dom was available.So the below code doesn't work.
var testElement = $("#testElement");
this.hideElement = function(){
testElement.hide();
}
For DOM manipulation it is better to go with directives than services.
I have some feature tests that run with a fixture (loaded with jasmine-jquery) that has some Knockout bindings in the HTML. At the begin of each test I want to start with a viewModel in its initial state.
If I call applyBindings() in the beforeEach() with a new instance of the viewModel I get this error from Knockout
Error: You cannot apply bindings multiple times to the same element.
If I try to revert the properties of the existing viewModel to match its initial state I still get an error. I believe this is because the fixture's HTML is removed after each test - this probably breaks the bindings?
I've also tried a suggestion that came up when Googling which was to use the cleanNode function in Knockout. This isn't part of the API (it only designed to be used by Knockout internally) and no matter what I tried it didn't resolve the issue.
It feels like I'm taking the wrong approach to this. tl;dr; How does everybody else test Knockout with Jasmine?
Thanks for any help
I generally append an element in beforeEach, apply bindings to that element, and ko.removeNode on it in afterEach. Something like:
var fixture;
beforeEach(function() {
fixture = document.createElement("div");
document.body.appendChild(fixture);
});
afterEach(function() {
ko.removeNode(fixture);
});
Then use fixture as the second argument to any applyBindings calls like: ko.applyBindings(myTestViewModel, fixture);
The way I solved this was changing my js to check for jasmine e.g.:
if (!window.jasmine)
ko.applyBindings(viewModel);
Here's a fiddle for this question (add/remove single slash on line 5 and re-run)
Basically, two ways of binding (proper term?) my application template. I would expect both ways to work, but one works, and one doesn't.
Works
this.register( 'view:application', Ember.View.extend());
this.register( 'template:application', Ember.Handlebars.compile( 'Hello, world!' ));
Broken
this.register( 'view:application', Ember.View.extend({
'template': Ember.Handlebars.compile( 'Hello, world!' )
}));
This seems to be the case for all resources/routes, not just at the application level.
So, why doesn't the second method work?
Edit: Here's a another fiddle that shows a Handlebars view helper successfully using method 2 (broken) above. It seems it's only an issue for route views.
Edit 2: Thanks to c4p Here's an Issue on Github
Have a look at this related question.
Short summary:
Ember expects to find templates in the global variable Ember.TEMPLATES. When you use Ember.Handlebars.compile, the compiled templates are put into the global variable Handlebars.templates.
If you want to use the compiling this way, you have to do something like this:
Ember.TEMPLATES['posts-template'] = Ember.Handlebars.compile('I am the template');
App.PostsView = Ember.View.extend({
templateName: 'posts-template'
});
I have seen a mention of using JQuery tmpl in a faster way to create a string instead of DOM elements: http://riley.dutton.us/2010/10/12/jquery-templates-vs-jqote-2-a-followup.html
I just can't seem to get it working though. I am using JQuery 1.6.4 and the latest tmpl files from GitHub. My code is below - can anyone point out the obvious mistake? Many thanks.
JsonData is a response from a web service and is correctly formed JSON - I can bind it using the well publicised approad to tmpl and also using JQote2.
jQueryTemplate looks something like:
<script id="jQueryTemplate" type="text/x-jquery-tmpl">
<li><span>${Name}</span><span>${ProductName}</span></li>
</script>
My JS to call the template:
var myTemplate = $('#jQueryTemplate').template();
var html = myTemplate($, { data: JsonData }).join('');
$("#container").html(html);
I seem to get undefined as the result of $('#jQueryTemplate').template(); and this error:
Uncaught TypeError: Object
<li><span>${Name}</span><span>${ProductName}</span></li>
has no method 'join'
Thanks for any help given.
define your template like this;
$.template( "jQueryTemplate", "<li><span>${Name}</span><span>${ProductName}</span></li>" );
render your template like this;
$.tmpl( "jQueryTemplate", JsonData ).appendTo( "#container" );
or
define your template like this;
<script id="jQueryTemplate" type="text/x-jquery-tmpl">
<li><span>${Name}</span><span>${ProductName}</span></li>
</script>
render your template like this;
$( "#jQueryTemplate" ).tmpl(JsonData).appendTo("#container" );
After much digging I eventually found an example of this approach explained by Boris Moore. Thanks Boris for your great work.
https://github.com/jquery/jquery-tmpl/issues/50
I created a jsperf to compare the two approaches - it is my first jsperf so hopefully it is set up correctly to get meaningful results. It shows a massive difference. I guess it depends on usage but mine is pretty basic markup generation so the string output combined with .html() will do the trick.
http://jsperf.com/jquery-tmpl-as-string
Hope this helps if you find yourself needing to improve tmpl performance and don't have the opportunity to switch to another templating engine.