I would like to use Ember.js with a website template from Themeforest (with html, css and js files).
A problem with the main Javascript file from the template is that it is called only one time when the document is ready, but I would like to call it each time a user change his route.
For example, each time a new route is called, there is a new <div class="page-content"></div>, but the following jQuery line is not executed.
$('.page-content').wrapInner('<div class="page-content-inner"></div>');
Do you have any idea to solve this issue with a clean way? I don't want to change every line of the main Javascript file of the template that has about 1200 lines.
Thank you for your help
You could use this example from the Ember docs on how to add Google analytics tracking on every transition.
App.Router.reopen({
notifyGoogleAnalytics: function() {
return ga('send', 'pageview', {
'page': this.get('url'),
'title': this.get('url')
});
}.on('didTransition')
});
The code above would get run each time you transition between routes, and you could just define it in one place.
Related
Basically trying to animated my 25+ divs (square blocks, regular height width 100px bg-color: blue) but in angular because I have three routes. I want my homepage to have the animation. I will figure that out. But for now, I want to link this code below into my angular app. Do I put it in the controller? Make a new script.js file and link it?
$(document).ready(function() {
$('.blockone').mouseenter(function() {
$(this).animate({
height: '+=40px'
});
});
$('div').mouseleave(function() {
$(this).animate({
height: '-=40px'
});
});
$('div').click(function() {
$(this).toggle(200);
});
});
To use jQuery, simply ensure it is loaded before the angular.js file. You can also use the ngJq directive to specify that jqlite should be used over jQuery, or to use a specific version of jQuery if multiple versions exist on the page.
you haven't shared enough code to be able to say exactly whether your solution would work.
assuming you have synchronous script references to your angular controller right before the closing body tag, leaving it in your controller may execute but this is frowned upon and cannot be reused in other controllers without repeating the code. you could have this code in a service, and inject it in the controller.
if you wanted to load it as a separate file, you could load it asynchronously with jqlite's $http or jQuery $.ajax.
I have this giant code, which is not necessary show here, but he will manipulate this div:
<div data-calendar="true"></div>
Finding like this:
var calendar = $('[data-calendar]');
The script works if the tag is within my main angular layout file, but when the tag is within a angular template file, the script does not work at all.
How fix that? I already put this script after the angular scripts, in order to make the angular scripts run before, but didn't work at all.
Including the script in the template is never going to work, you need to be able to control when it runs so that it will run any time that div is added, replaced, etc which could happen any time a digest happens.
The best way to do that in this case would be with a directive.
<div calendar></div>
.directive('calendar', function() {
return {
link: function (scope, element) {
element.jqCalendar(); // jQuery plugin should be avail here, if you included jQuery and the plugin before angular.
}
};
});
I'm looking for best practices for using javascript/jQuery snippets in an asp.net project. I know that it is best to put all the scripts in a separate file rather than inline. That's good. It is easy to move these script functions to a common file (may be a couple of different ones to even out the performance of loading a single large file for small functions).
But there is some jQuery stuff that needs to happen on document.Ready on each page. How will I move this to a common .js file? I would like to avoid one script per page as it would be just too many.
For example, say Page1 has a need to manipulate a few radio buttons on load and has the following script inline. (just for illustration)
<script>
$(document).ready(function() {
//check checkboxes
if(true)
call function1();
});
</script>
Same with Page2 but for some other condition, calling different function function2.
I can move the function1 and function2 to a common .js file but how about the document ready sections. Should that stay inline? I assume so because otherwise I'm not sure how the common.js will differentiate between document.ready for different pages.
Then does it defeat the purpose of not having inline javascript? If anyone can throw some light into this, it is much appreciated.
I did some research, but probably due to incorrect keywords, so far I haven't been able to find any good information along the same lines. Unobtrusive JavaScript seems promising in the comments below.
You should specify what behaviors should exist within the HTML using data-* attributes.
You can then use a single universal piece of Javascript code to read these attributes and apply behaviors.
For example:
<div data-fancy-trick="trick-3">...</div>
In the JS file, you can write something like
$('[data-fancy-trick]'.each(function() {
var trickName = $(this).data('fancy-trick');
switch (trickName) {
...
}
});
For real-life examples of this technique, look at Bootstrap's Javascript components.
You can simply have separate js files per page and include them in relevant pages. For shared script code, have a common js file. Following your example:
common.js
var myCommonVar = {};
function myCommonFunction(...){
...
}
page1.js
$(document).ready(function() {
...
function1();
...
});
page2.js
$(document).ready(function() {
...
function2();
...
});
page1.html
...
<script src='/js/common/js'></script>
<script src='/js/page1.js'></script>
...
page2.html
...
<script src='/js/common/js'></script>
<script src='/js/page2.js'></script>
...
Consider the usage of AMD (Asynchronous Module Definiton) design pattern. Put your JavaScript code into modules and on each page use just those you really need to. For example requirejs does a great job and I've been using it with success. If you have a bigger project you can split your modules into namespaces. This approach will keep excellent code maintainability and it's reliable. You simply put the "starter" javascript file on each page and load only those required modules you need to work with per each page.
There are many ways to deal with this problem, either using a JavaScript Framework that is aiming to treat your website as a 'Webapp' (Angular and Ember among the popular), or using your own custom script that will do just that - invoking the appropriate JavaScript per loaded page.
Basically, a custom script that will be able to handle it, will have to make use of (pseudo) 'Namespaces' to separate modules/pages code sections.
Assuming you have 2 hypothetical pages, Home and Browse, Simplified code sample may look like this:
HTML:
<body data-page="Home">
Global.js:
var MyApp = {}; // global namespace
$(document).ready(function()
{
var pageName = $('body').data('page');
if (pageName && MyApp[pageName] && MyApp[pageName].Ready)
MyApp[pageName].Ready();
});
Home.js:
MyApp.Home = MyApp.Home || {}; // 'Home' namespace
MyApp.Home.Ready = function()
{
// here comes your 'Home' document.ready()
};
Browse.js:
MyApp.Browse = MyApp.Browse || {}; // 'Browse' namespace
MyApp.Browse.Ready = function()
{
// here comes your 'Browse' document.ready()
};
MyApp.Browse.AnotherUtilFunc = function()
{
// you could have the rest of your page-specific functions as well
}
Also, since you're using ASP.NET MVC, sometimes your Controller name may fit as the qualified page name, you can set it automatically in your Layout.cshtml (if you have one):
<html>
<head>
</head>
<body data-page="#ViewContext.RouteData.Values["Controller"].ToString()">
#RenderBody()
</body>
</html>
I think its not worth stuffing up everything in a single file and separating them with conditional statements, just to avoid adding a reference on the respective file.
If you have code that can be called on 2,3 or more pages, then we can opt for having them in a common file. But if its going to be called on a single page then we must write code on the respective page only. This will also increase the overhead of declaring the functions that are not going to be called on the current page
And when you are using the common js file, then you don't need to worry about the $(document).ready(); event, you can use a single ready event in the common file and separate the code by using conditional statements.
The new versions of the script manager will combine everything into one blob of a script. In theory it makes fewer round trips and things run faster. In practice you could end up with several large scripts that are nearly identical and each page needs its own blob of a script. If your making one of those never change the url website pages then this is the way to go.
I came up with these best practices when I was working with jquery on ASP.Net
Load Jquery in your master page above the first script manager. Jquery is now available on every page. The browser will only get it once and cache it.
If bandwidth is an issue use a jquery loader like googleload or MS content delivery network
Document.load is always at the bottom of the page to guarantee that everything needed is already loaded.
From my blog that I haven't updated in years...Google Load with ASP.Net
One common way to address this problem would be to have your common script include followed by a per-page script element:
<!-- In 'shoppingcart.html' -->
<script src="main.js"></script>
<script>
// Let there be a onDomReady JS object inside main.js
// that defines the document.ready logic on a per-page basis
$(document).ready(onDomReady.shoppingCart);
</script>
Great question, I have been dealing with the same thing.
Here is what I have been doing:
Have your $(document).ready() call different init functions (if they exist), where each .js file has its own init which adds event listeners and loads functions, messes with css, etc.. Each .js file is separated out into different pieces of functionality.
This way you have one document ready that calls all of your initializers. So each page would include the .js functionality it needs. This way you can separate out what is different.
ex:
ready.js:
$(document).ready(function(){
if (typeof menuNavInit == 'function'){
menuNavInit();
}
if (typeof menuNavDifferentInit == 'function'){
menuNavDifferentInit();
}
//other .js functionality
});
menuNav.js
function menuNavInit(){
$("#menu").on('click', menuNavClick)
}
function menuNavClick(){
//do something
}
menuNavDifferent.js
function menuNavDifferentInit(){
$("#menu").on('click', menuNavDifferentClick)
}
function menuNavDifferentClick(){
//do something else
}
page1.html
...
<script src='scripts/ready.js'></script>
<script src='scripts/menuNav.js'></script>
...
page2.html
...
<script src='scripts/ready.js'></script>
<script src='scripts/menuNavDifferent.js'></script>
...
In large scale application, our web application might be organize into separate partial page in order to increase the modularity of our application. In some case compiling a partial page loaded through XHR or Ajax request either using Angular $http.get or JQuery $.load will introduce an error.
Using my scenario as example, exactly I'm using Kohana PHP framework so i can control the modularity of my web application on the server level. As usual all template and page been separate into view, leaving all HTML, JS and CSS together on presentation layer.
This will giving an great flexibility for me to implement the Javascript MVW/MVC stack on client side processing as my web app are heavily depend on AJAX request to fetch data from back end application. In my scenario im using AngularJS and below is a simple pseudo on how the data from Model presented to client.
Kohana Model > Kohana Controller > Kohana View > XHR > JQuery\Angular > DOM
One of my part in my application that really give me bump and get me drink few bottles of metabolism drink to solve the application. Is where i have a Modal dialog and the partial page are load through XHR from server and attached it to selected DOM.
The problem is when Angular try to compile the partial page, when it found the ng-controller directive it will be looking for the function referring to the processed directive. Error were produce where the controller is not found as it not yet evaluated by DOM parser. But when you pre-delare the function somewhere in your application just before your load the partial page, everything is OK. Below is the example on how i setup a Dialog service that will be called from link directive when i clicked the said link.
var dialogService = angular.module('dialog.service', []);
dialogService.factory('Dialog', function($http,$compile){
var dialogService = {};
dialogService.load = function(url, scope){
$("#dialog:ui-dialog").dialog( "destroy" );
$("#dialog").attr('title','Atlantis');
$http.get(url).success(function (data) {
html = $compile(data)(scope);
$('#dialog-content').html(html);
$("#dialog").dialog({
width: '600px',
buttons: {
"Ok": function() {
$( this ).dialog( "close" );
return true;
},
},
close: function(){
if (typeof (onClose) == 'function') { onClose(); }
},
});
});
}
return dialogService;
});
After some research i have found some solution and sharing it with fellas on my answer for others beginner like me. (sorry for my English).
There's nothing wrong on AngularJS on this setup, others JS guru out there might already know the solution and very busy to share with us while inventing another cool web development tools or framework. That's OK keep doing that. This might not be a cool or ultimatum solution, please share any improvement or tips with us!
To overcome this problem we need s strategy to setup, let me start with an example code so our brain will digest while the information flowing through. Below code is the placeholder where i create the the modal dialog using JQuery and the Ajax content will be insert.
<div ng-app="asng" id="dialog" title="" style="display:none">
<div id="dialog-content"></div>
</div>
As a basic knowledge, we have to understand on how DOM parser are working. We might think that DOMP (DOM Parser) is a multi-threaded and that's the reason we can load multiple external resource in parallel. Actually DOMP are single threaded while parsing the DOM elements index from top to bottom. Below is the example on the partial page that I'm gonna load into #dialog-content DIV element.
<script language="JavaScript" type="text/javascript">
function Transaction ($scope,$http){
$scope.items = [{"country":"VN","quantity":"100"}];
$scope.country_name = $scope.items;
}
</script>
<style>
</style>
<div id="transaction-panel" class="user" data-ng-controller="Transaction">
<form id="{{ form_name }}" action="">
Country : [[ items.country ]] </br>
Total : [[ items.quantity ]]
</form>
</div>
Actually these partial still giving an error, although we have put the script block just before the element with ng-controller directive. Actually that's not really the case, the part that we need to tackle is how AngularJS compile service are compiling the partial DOM. Let go back on my question part above and inspect where the line that we do the compile thing.
html = $compile(data)(scope);
$('#dialog-content').html(html);
First line above will compile DOM in data variable, and insert into the root DOM unfortunately first line will shout an error : Controller Transaction not found.
This happen because, the Script Block in your partial page is not yet evaluate by DOMP parser because is not inserted into the root DOMP. Now you see the light OK, so we have to change the compiling strategy a bit, by inserting the new DOM and then we will parse back the inserted DOM look example below:-
html = $('#dialog-content').html(data);
$compile(html)(scope);
Slim and simple solution, it took me few head banging morning to solve this problem just because ignoring the simple concept on DOM parsing.
If I understand what you are trying to do, here's a simple example.
I wanted to post via AJAX to a Django form and then replace the form content in the page with the returned markup. The returned markup includes an ng-controller, which I need to execute when it loads:
.controller('MyForm', function($element, $compile, $scope){
var scope = $scope;
var $theForm = $element;
var $formBlock = $element.find('.the_form'); // is replaced by the form response
$element.find('.submit_the_form').click(function(){
// submit the form and replace contents of $formBlock
$.post($theForm.attr('action'), $theForm.serialize(), function(response){
var newstuff = $formBlock.html(response);
$compile(newstuff)(scope); // loads the angular stuff in the new markup
});
});
})
I think the line you're interested in is $compile(newstuff)(scope);
EDIT:
Crikey, tried this with some other markup this morning and did not work, for no reason I could figure out. Turned out that if I did not have a field with ng-model assigned, in the new markup, then the $compile does not execute. Added:
<input type="hidden" name="dummy" value="0" ng-model="dummy"/>
...and now it compiles.
Im doing an embed code for our clients, so the clients could have multiple embed of our code (cant do it over iframe). I would want to try requirejs to do it, so my question is if i have multiple requirejs on the same page, both load different js with different paths+shims, will the oncomplete function for both of them work?
like the client would have on the main content (on their cms on specific page)
<script src="myexample.com/video.js?key=123"></script>
and on the sidebar (on their cms on all pages)
<script src="myexample.com/content.js?key=123"></script>
so my video.js would have
require.config({path: { video : '' }..., shim : {} ....});
require(['video','utils'], function(){ do something on video });
and the content.js would have
require.config({path: { content : '' }..., shim : {} ....});
require(['content','dom'], function(){ do something on content });
From what i go from here https://groups.google.com/forum/?fromgroups=#!topic/requirejs/MwQ-CNHxGKc it seems not possible that the 2 functions would be executed, meaning it would only process one of them.
If its not possible in requirejs can someone point me to other amd loaders where its possible. Thanks
You could use one loader with a minimal function that start both of your modules:
require(['video','content'], function(video, content){
video.start();
content.start();
});
Have a look at how Shootitlive solved it with their widget
One can pass arbitrary parameters to each embed
The embed code is short
It loads asynchronously
One can have multiple players on one page
http://shootitlive.com/2012/07/developing-an-embeddable-javascript-widget/