Underscore templates with backbone boilerplate, correct way of doing it, or is there a better template method - backbone.js

Ok, I am playing around with Backbone, node.js, Underscore, Backbone Boilerplate so I have enough knowledge. Been asking questions like crazy as I still can't quite get my head around it. I am currently attempting to use the Underscore library with Backbone Boilerplate to make a very simple template which will allow me to pass in data; then when the model is updated, change the view which would change the template. I believe this is the correct way of doing it, instead of writing HTML code inside my JS file? Stop me if I'm wrong.
The Backbone Boilerplate has its template .fetch() system which I understand. However it would mean writing HTML in my JS I believe. So I wanted to use Underscore to simply pass information from the model to the view to the modules to render the template again (or I might be able to skip the view completely?).
My question is why won't this work, I think it's because I'm not changing it to JSON.
My HTML template:
<div>
<script id="rtemp" type="text/x-underscore-template">
<span><%= title %></span>
</script>​
</div>
And the JavaScript:
define([
// Global application context.
"app",
// Third-party libraries.
"backbone",
"underscore",
"json2"
],
function(app, Backbone) {
var Attempt = app.module();
Attempt.Model = Backbone.Model.extend({});
Attempt.Collection = Backbone.Model.extend({});
Attempt.Views.Tutorial = Backbone.View.extend ({
template: "app/templates/attempt",
render: function(done) {
var tmpl = app.fetchTemplate(this.template);
//console.info(tmpl);
this.$el.html(tmpl({title: 'This is a title'}))
}
});
return Attempt;
});
When I inspect the element it shows in the <div> however it still has the template script tags around it so doesn't show on the page in HTML. I tried using json2 to convert it to JSON first, but that didn't seem to work unless I did something wrong. Is Underscore the best thing to use? I assumed so as it's a Backbone dependency. Or should I use something else. I just want to avoid writing HTML in my JS.

If I understand you right, you're ending up with this HTML:
<div>
<script id="rtemp" type="text/x-underscore-template">
<span>This is a title</span>
</script>​
</div>
That's the right behavior based on the code you're using but that's clearly not the result you want.
The <script> wrapper for templates is used when you're embedding the template inside an HTML page. This is done so that the browser won't try to interpret your template as HTML and to keep the browser from trying to render it on its own. In such cases, you'd have the template embedded in the HTML page like this:
<!-- Some HTML stuff... -->
<script id="rtemp" type="text/x-underscore-template">
<span><%= title %></span>
</script>​
<!-- Some other HTML stuff... -->
and you'd use it like this:
var t = _.template($('#rtemp').html());
var html = t(...)
The $('#rtemp').html() part extracts just the content of the template's <script> wrapper so _.template would only see <span><%= title %></span> and the final processed template would just be a simple <span>. For example: http://jsfiddle.net/ambiguous/dzPzC/
In your case, you're reading the entire <div><script>...</script></div> as the template and feeding that to _.template. The result is that tmpl({title: 'This is a title'}) still includes the <script>, the browser doesn't know what to do with a <script type="text/x-underscore-template"> so the <span> that you're interested in doesn't get rendered at all.
You don't need the <script> wrapper at all, that's only needed when you're embedding a raw template inside some HTML. Your template only needs the the content of your <script>:
<span><%= title %></span>
Demo: http://jsfiddle.net/ambiguous/QuwSX/
The argument that you're passing to the template function:
tmpl({ title: '...' })
is fine, the compiled template function just wants to see a JavaScript object. People talk about passing it JSON and often use the toJSON method to prepare data for the template but that's an abuse of terminology; the template really wants an object and JSON is, technically, a string.

Related

AngularJS: Script tag not working in ng-include

I have a file index.html with the following code:
<div ng-include="'fragment-1.html'"></div>
The code of fragment-1.html:
<b>Inside Fragment 1</b>
<script type="text/javascript">
alert("Inside Fragment 1");
</script>
When I load index.html into the browser, output is:
Inside Fragment 1
The DOM has the <script> tags but the alert is not shown.
My hypothesis:
Because the DOM loads first along with the Angular modules and then Angular checks and binds the data(in this case, fragment-1.html file content) to the view(index.html), it just adds the elements of fragment-1.html in DOM. To execute the JS inside fragment-1.html, we should create a hack for it. Am I right in this explanation? Or is there something else that I may be missing?
I had to load jQuery before loading Angular. The explanation is in the link specified above. Explanation: script not running in templateurl
To include another partial HTML file in your parent HTML file, one can also use Angular directives, depending on the situation. See this answer for when to use ng-include and when to use directives: https://stackoverflow.com/a/24172025/3132646
You don't need to hack. Angular gives you a neat and simple solution to what you want to achieve with your code.
Controller
.controller('fragmentOneCtrl', function ($scope) {
alert('"Inside Fragment 1"');
})
View
<div ng-repeat="go in ['go', 'gogo']" ng-include="'includeThis'">
</div>
<script type="text/ng-template" id="includeThis">
<div ng-controller="fragmentOneCtrl">
</div>
</script>
You may want to use $sce.trustAsHtml before injecting the resource in html

Front-end design: Dynamically add items to list

So, I've tried several times to thrust myself into the world of website development. Each time, I have abandoned a project for one simple reason: lists.
I would like to know, from front to back, the dataflow for a system which follows the following sequence of events:
The user is shown a list in a website
The user fills out a new list item in some sort of modal dialog
The user hits "Submit" and that item is now added to the list.
That new list item is sent to the server to be stored
Would there be a whole new page load? When would the data be posted to the server? What are the various options for this (seemingly simple) application? I am targeting relatively small web tools. Not necessarily single page, but I'm not against it.
I understand how to add the new <li> to a list with JQuery, and I know how to build the modal with HTML. I can pull the data from the modal, but I'm not sure how to take that data from JQuery, turn it into the appropriate block of HTML (which could be rather complex), and store the new record in the database.
I can't seem to find a tutorial on this sort of data handling.
Thank you!
Simple. Since you mentioned jQuery, let's use jQuery. Ready? Here we go!
I'm assuming you have a textarea or an input in your modal where a user can enter text. If so, give it an id attribute so it can be referenced, like id="myText".
Then, to take the textarea or input's content and turn it into a list item in your list, you'll need to append an <li> with the textarea's content to its parent <ul> tag. Again, you'll need some way to reference the <ul> tag, so give the <ul> tag an id attribute, something like myList, so it becomes <ul id="myList">.
Now, it's just a matter of taking the val()ue from the input field, and appending it to the list. This is how you do that.
var textareaStuff = $('#myText').val();
$('#myList').append('<li>'+textareaStuff+'</li>');
That wasn't so hard, was it? This is actually quite fun.
I will admit, POSTing stuff to the server may take some getting used to, but it's not too hard.
I've prepared an HTML file for you that does all these things, with pretty detailed documentation. It should be able to help you learn what you're wanting to learn. It's below.
<!DOCTYPE html>
<html>
<head>
<title>My jQuery Experiments</title>
</head>
<body>
<!-- Here's your list with its ID so we can reference it in JS. -->
<ul id="myList">
<li>Sample Item 1</li>
</ul>
<input id="myText"> <!-- Here's your input field. This can be in a modal. -->
<button id="addItemButton">Add Item</button> <!-- We need a save button. -->
<!-- Include jQuery -->
<script type="text/javascript"
src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<!-- This is the javascript you'll need to write and understand -->
<script type="text/javascript" >
// When the element with id="addItemButton" is clicked,
$('#addItemButton').click(function() {
// Append the stuff in brackets to the element with id="myList"
$('#myList').append('<li>' + $('#myText').val() + '</li>');
// ^ The stuff in brackets is an li code with the value of the HTML
// element with id="myText", your input field above.
// Now to post it to a server, we'll need to use AJAX.
// Luckily, jQuery has an AJAX function. It looks like this:
$.ajax('http://example.com/mysaver.php', {
// We're POSTing stuff to the server.
method: 'post',
// This is the data to send to the server.
// It is a JSON object.
// If using PHP, you'll get $_POST['item'] = whatever is in id="myText"
data: { item: $('#myText').val() },
// If the AJAX request was successful,
success: function(data) {
// The argument 'data' contains whatever the server returned.
},
// If not,
error: function(jqXHR) {
// Handle your error here.
}
});
});
</script>
</body>
</html>
I hope this was helpful! Go ahead and approve this answer if it was, and please feel free to ask further questions in the comments and I'll do my best to help out where I can.

AngularJS insert invalid HTML

I have an app that requires HTML to be pieced together from different APIs. Rather than getting into specifics there, let me just say that we have tried getting away from that many times but in the end the best answer always end up being what we currently have. Hopefully that changes someday but for now it's working great.
Currently, the HTML is parsed together as a string server-side using NodeJS and sent across the wire as complete HTML to be rendered. I'm in the process of adopting AngularJS, and while I'm loving it I am stuck on this issue-- how can I use Angular templating to insert invalid HTML at times?
The server will return three JSON fields: leadingHTML, trailingHTML, and copy. The copy field is always valid HTML, but leadingHTML and trailingHTML can sometimes return invalid HTML. When all three are added together, valid HTML results.
Let me illustrate:
leadingHTML='<figure>';
copy = '<img src="img1.jpg"/><img src="im2.jpg"/><figcaption>I love AngularJS</figcaption>';
trailingHTML='</figure>';
As you can see, if you add those together you will get the valid HTML that is required to be displayed. It's pretty easy to make the fields trustworthy HTML in Angular:
for (i in data.results){
data.results[i].copy=$sce.trustAsHtml(data.results[i].copy);
data.results[i].leadingHTML =$sce.trustAsHtml(data.results[i].leadingHTML );
data.results[i].trailingHTML =$sce.trustAsHtml(data.results[i].trailingHTML );
}
And then render the copy in my view:
<div ng-repeat='i in data.result'>
<p ng-bind-html='i.copy'></p>
</div>
But I need a way that does what this looks like it would do, but the leadingHTML and trailingHTML scope variables get render as strings:
<div ng-repeat='i in data.result'>
{{ i.leadingHTML }}
<p ng-bind-html='i.copy'></p>
{{ i.trailingHTML }}
</div>
Is the best answer here to build the template via javascript? Would that even work?
Are you able to pre-process your data so that you do have valid HTML?
var item;
for (i in data.results){
item = data.results[i];
item.content = $sce.trustAsHtml(item.leadingHTML + item.copy + item.trailingHTML);
}
Then you can just bind to the combined content in the view:
<div ng-repeat='i in data.results'>
<div ng-bind-html='i.content'></div>
</div>
Edit:
Yes, this will allow you to embed expressions in your HTML content.
In fact, you will need to be careful that you aren't opening yourself up to security exploits in the trusted HTML content (see the example at the bottom of the page for the $sce service).
Using $sce.trustAsHtml in this way is roughly equivalent to loading a directive's templateUrl from your site, so the security considerations around that are probably the same. See the "How does it work?" and
"Impact on loading templates".

How can I display HTML in a <div> with Angular 1.2.0 - rc2

I am trying to display some HTML in my web page and using the following:
xx {{ pageHtml }} yy
<div data-ng-bind-html-unsafe="$scope.pageHtml"></div>
The data between xx and yy shows up as raw HTML but what I want is to not show it as raw. I used the code on the second line but nothing shows.
Is there something I am missing? Did something change in 1.2 because I thought this was working before?
Update - I do 100% trust the HTML and don't want to clean it. There will be code inside the HTML that needs to show on the screen.
By default the innerHTML-ed expression result is sanitized using the $sanitize service which would require you to include ngSanitize in your module's dependencies.
<div data-ng-bind-html="pageHtml"></div>
However if you trust the HTML to be safe, you can bypass sanitization using $sce service that you would inject in your controller:
$scope.someSafeContent = $sce.trustAsHtml("<i>Hello</i> <b>World!</b>");
HTML:
<!-- bypasses sanitizaton -->
<div data-ng-bind-html="someSafeContent"></div>
Controller
myApp.filter('unsafe', function($sce) { return $sce.trustAsHtml; });
In View
This will resolve your problem.

AngularJS - load dynamic template HTML within directive

I have a directive which loads content from an external HTML file. Passed into this directive is some scope data which is used in the rendering of that HTML fragment. e.g.
<div class="{{cls}}" data-obj="{{obj}}" data-id="{{id}}">
<!-- remainder of content here -->
</div>
What I would like to do within this directive is to load a further HTML partial within this based on the original scope data passed into the directive. I can't seem to get this to work, but it should be something along the lines of the following:
<div class="{{cls}}" data-obj="{{obj}}" data-id="{{id}}">
<!-- remainder of content here -->
<div ng-include="partials/{{obj}}.html></div>
</div>
Using this, the file doesn't get included, but I don't get any errors either. Can anybody assist me here?
NB: I read this, which is a similar issue, but hasn't helped me.
UPDATE - I noticed in Chrome dev tools that the URL is being resolved as expected, but the file contents are not getting included. I thought from the docs that ng-include loaded and compiled the requested fragment, so I was expecting this to work.
Found a solution in the end, by declaring the following in the directive:
<div ng-include src="view.getView()"></div>
and the following in the directive controller:
$scope.view = {
getView: function() {
return "partials/" + $scope.obj + ".html";
}
};
Works perfectly now!
In comment on the comment of Shane Gadsby: it is not <div ng-include src="'partials/'+{{obj}}+'.html'"></div> but <div ng-include src="'partials/'+obj+'.html'"></div>.
Your comment explains why 'this is what you need to force it from object literals to a string', so everything not in single quotes is handled by the compiler as a scope object.

Resources