Backbone.js not performing document.write at the correct time? - backbone.js

I have a backbone.js CMS of sorts, that accepts html and then renders it in the browser. The following is the template file (in .hamlc) that renders the backbone page object.
%h1.text= #page.get('title')
.text.page-content!= #page.get('content')
This works fine, until I have a <script> tag. I have a script tag for a widget (below)
<script src='http://www.opentable.com/frontdoor/default.aspx?rid=52900&restref=52900&bgcolor=8AA86B&titlecolor=0F0F0F&subtitlecolor=0F0F0F&btnbgimage=http://www.opentable.com/frontdoor/img/ot_btn_black.png&otlink=FFFFFF&icon=light&mode=short&hover=1'></script>
This widget uses document.write (which you can see if you look at the source). First, when I load the page it doesn't show anything (I've tested the widget in an html file by itself and it displays their normal god-awful ). When I inspect the element, it looks like the script tag was removed.
However, when I test with the following:
<script type="text/javascript">
alert(0);
</script>
It runs. Still nothing in the inspector though.
Finally, testing with the following:
<script type="text/javascript">
document.write('test');
</script>
It also runs. However, it completely destroys the page content and just shows 'test'.
According to this article about using document.write for widgets, it says it can't be run after the page load. I'm assuming that's what's happening here is that document.write is being run after page load and destroying all the content, given that's the technique backbone.js uses (appending/replacing elements in the DOM once the page is loaded).
How can I make my Backbone.js CMS accept script tags with document.write widgets without either not showing anything or destroying the entire page?

I cannot reproduce it, the template renders as it should:
$ coffee
coffee> hc = require './src/hamlc'
{ compile: [Function],
template: [Function],
__express: [Function] }
coffee> template = hc.compile ".text.page-content!= #content"
[Function]
coffee> template(content: 'Hello <script>Script</script>')
'<div class=\'page-content text\'>Hello <script>Script</script></div>'
and the script tag is persisted. Do you have the latest version installed?

You're calling document.write after the page has been loaded, so it'll overwrite the whole page. You could try putting the script tag in an iframe, or monkey patch document.write to behave differently after the page has been loaded. See the top answer on this question:
Dynamically added JavaScript overwrite the html page view (not the code)

If I understand correctly, you're trying to include the script tag for the widget inside a template, which means it's being inserted after the initial DOM is ready. That won't work for the reasons you mentioned; when the script executes, it will replace everything in the DOM.
You need to load the script before the initial DOM is complete, that is either in <head> or at the beginning of <body>. That in turn means that you have to include the script tag in your initial HTML as delivered by the server rather than trying to dynamically generate it client-side.

Related

AngularJS preload pages (off line mode)

I would like to preload templates in AngularJS (with ng-route) so that when I am on the home page, after loading all the necessaries element, I can download some sub-pages of my application in order to, if the user lost connexion, he is still able to go on that page, without an internet connexion.
I tried to make different asynchronous calls on my pages but I'm not getting anywhere.
I hope it's clear
There are two approaches for this:
The first one is to use an Ajax call and get the HTML for your Sites and load it into the template Cache by yourself:
$http.get('./template.en.html').then(function (result) {
//put template into cache
$templateCache.put('myTemplateName', result.data);
});
The second would be to use OcLazyLoad:
$ocLazyLoad.load([
'path/to/template.html'
]);
But with this approach your Template files need to look like this:
<script type="text/ng-template" id="myTemplateName">
Content of the template.
</script>
Also you could load your controller files with ocLazyLoad

angular-slidezilla: <slider> not showing in site

I tried intgrating angular-slidezilla into a web site, but the slider elements do not show.
Observations:
I copied the .js file into the /lib folder and the .css into the /css folder.
the site uses requirejs; I added the source file into the requirements list.
I added the css as a stylesheet link next to the other css files in the index.html file.
To test, I copied the demo page (the entire part) into my HTML page and added $scope.slider1.val etc. variables to the AngularJS controller object. I also added a function which periodically changes the value of the scope variables.
When I deploy the site and load the page, I see the values changing every second (these are shown as text near the sliders). But the sliders themselves do not show.
"Inspect element" function shows a generated piece of DOM (div objects related to the slider), but the slider itself has size 0px*0px.
No errors in javascript console.
Can anyone give me a hint how to investigate further?
Found the solution. The javascript code in angular-slidezilla.js was never executed. As a result the widgets were not initialized and remained in their initial hidden state.
I needed to edit one line of javascript code to get it working:
// app.js
var app = angular.module("app", ['ui.bootstrap', ..., 'angular-slidezilla']);

Angular - Re-add a bootstraped module to DOM

I'm facing an interesting issue here.
I'm developing a Chrome Extension with a content script.
This extension is intended to add a little div to a page, this div using AngularJS. (I chose Angular because I want this div's data to be readily updated by change of var values).
I'm able to add the div once and bootstrap it. So the behavior of the div is fine.
But the main page (which I have no control over) often reloads everything using Ajax. (Then I'm totally unable - I think - to get events from certain elements being removed).
I was able to create ways to check if my elements are still on the page, and if not, they are added again. The appendChildPersistent method takes care of it. (It waits for a certain element to appear on the main page. Adds my element to it. Runs the callback when added. Keep checking if the element is still there, if not, repeat all over).
So all my ordinary elements work perfectly.
But this angular div cannot be bootstraped a second time.
Procedures:
I wait until a certain element appear on the main page
I add my own div myDiv from a plain text html using jquery append to the main page div
I load the angular application and bootstrap it using the callback function when the div is added:
Code:
var txt = '<div id="myDivId" ng-controller="myController">{{testing}}</div>';
appendChildPersistent('myDivId', MyDiv, '#theTargetMainPageDiv', function()
{
var app = angular.module('myApp', [])
.controller('myController', function($scope) {
$scope.testing = 'Welcome!';
});
angular.bootstrap(document, ['myApp']);
});
So, the first time my div is added, it works. The angular vars and directives work (in this example, the div shows "Welcome!"). But the second time, I get an "already bootstrapped" error. (But if I do not try to bootstrap again, the div becomes just plain text, no angular behavior, showing "{{testing}}" instead of "Welcome!").
Is there a way to unboostrap, redo bootstrap or another method I could work to get around this?
Your application only focuses on the div you insert. You can make an Angular application run on a certain area of the page instead of covering the whole document. Simply pass the DOM element to the bootstrap function:
angular.bootstrap(myDiv, ['myApp']);
This way Angular only runs in your div and you are able to bootstrap the app every time you add a new div.

Can I place ui-view on the body tag?

I'm working on an app whose header's styling and UI options will change depending upon the state a user is currently in. For example, if a user clicks the Upload, Edit Profile, Create Playlist or Create Gallery buttons in the main menu, this will cause the following changes to the header:
the header's background to change color
the site logo will have CSS3 animation applied to it to make it slide into a new position
a specific message (depending on what state the user is in) in a word bubble will appear next to the logo
a Cancel button will manifest on the right edge of the header
This means there will be no static element on my site so logic tells me that I should place ui-view in my body tag thus making it look like this:
<body ng-app="app" ui-view>
I have never seen that used before anywhere so I've my doubts. Any ideas?
I'm not sure if this will or will not work technically, but I believe you should avoid it because:
It would require all your templates to include an outermost <body> tag which makes them less reusable
It's generally an unusual thing to do, and that comes with a cost, and I see no particular benefit to this, so IMHO the cost/benefit analysis says stick with what is conventional: use <div>s.
I suspect this may in fact work, but typically the tag with ng-app stays in place for the entire lifecycle of the app. There's a chance you may hit some weird errors if you swap out the tag containing ng-app. Thus many people put ng-app on the very first <html> tag and call it done.
But it's your app and the effort to try both approaches is very low, so just try them out and see (and let us know what you learn). I don't think you need to wait for stackoverflow answer from authority to test 2 slightly different HTML structures with your app.
No, please do not do that!
Having ui-view inside of the body tag may render many JS plugins/libraries unusable, especially in case if they dynamically add some HTML tags to document.body. In such cases, navigation to another view will reinitialize document.body and thus disregard previously added HTML tags.
E.g. this is the case with Firebase and Angular.js (AngularFire). I hope everybody who has come across the error
Uncaught NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
will get to see this post. Just make sure you haven't added ui-view attribute to your body tag.

Web app attempting to retrieve data before AngularJS is loaded

I am adding images to divs with ng-repeat which works fine. The image location data is nested in an array. The images show up as expected. My partial looks like:
<div class="image-wrapper">
<img src={{item.user.img_src}}>
</div>
However, it appears the page is to attempting to retrieve the string before AngularJS is loaded. I get the following console warning:
GET http://localhost:3000/%7B%7Bitem.user.img_src%7D%7D 404 (Not Found)
How do I prevent this?
The src attribute is buggy when Angular markup is used. Use ngSrc instead of src.
Thus, <img ng-src="{{item.user.img_src}}">
When the browser first loads the page it sees your src exactly as you wrote it. It's not until Angular loads and processes the page that it updates your dynamic source. Neither of these is what you want to have happen (especially since you could accidentally create the bad empty src attribute). Instead, use ngSrc directive so that no src will be set until Angular has evaluated your expression:
http://docs.angularjs.org/api/ng/directive/ngSrc

Resources