ClientDependency Framework & Razor, add custom JS - javascript

I'm trying to get the hang of ClientDependency Framework.
https://github.com/Shazwazza/ClientDependency
I use it in an Umbraco website.
I'm having a problem with some custom javascript (not in a file) that I want to run.
I want to run a function (which is in "functions.js"), but with a different parameter per page.
So, I add the following to my template:
Html.RequireJs("~/scripts/functions.js", 1);
And on my masterpage before the -tag I've added:
#Html.RenderJsHere()
But where do I place my function-call? I can't just add it to my template, because "functions.js" isn't loaded yet (it's at the bottom of my masterpage).
I've thought about creating a js-file for each call and add them to the Html.RequireJs(...) but that isn't a great solution.
Is there a way to add inline-script to the list of "JS-to-render" ?
edit:
I was just trying to get it to work using RenderSection(), but that doesn't seem to work when the section is defined on a macro?
edit:
I don't have the code here at the moment I'm typing this, but the idea is like this:
functions.js
function WriteToConsole(input) {
console.log('Log', input);
}
template1.cshtml
#{Html.RequireJs("functions.js");}
<script>
WriteToConsole("This is from template 1");
</script>
template2.cshtml
#{Html.RequireJs("functions.js");}
<script>
WriteToConsole("This is from template 2");
</script>
master.cshtml
<body>
#RenderBody()
#Html.RenderJsHere()
</body>
Just to give an idea of what I'm trying to do.
As you can imagine, the <script> part on my template is now being called before functions.js is included. And this results in an error.
Or am I handling this whole thing wrong?

Are you trying to alter the script call in: Html.RequireJs("~/scripts/functions.js", 1); ?
So something like Html.RequireJs("~/scripts/functions.js?myparam=xyz", 1); Is this what you are trying to achieve but having the url be dynamic?
If so you could do something like this :
//perhaps have some logic above to determine what the query should be and concatenate it to the string like so.
string query = "?myparam=xyz";
string scriptcall = "~/scripts/functions.js"+query ;
Html.RequireJs(scriptcall, 1);
Could you provide more code so we can see what you are trying to do? Maybe list in steps on how it should work?

Related

How to pass element ID variable to jQuery load function

I am fairly new to Jquery and HTML so please bear with me. I have my index.html with a call to jquery-1.9.1.min.js and I want to create a script that would load an outside html file. Index.html is a fairly long file so I want to break up the section for cleaner code and make it easier to modify.
<html class="no-js">
<main>
<section id="testLoad"></section>
</main>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
<script>$("#testLoad").load("test.html #part-1"); </script>
</body>
</html>
As you can see from the code above it loads the html file fine. What I want to do is set "#part-1" as a variable so that I can call the load script again but call a different ID from another part of the file.
I would also be open to different methods aside from this load function. All I need is to call an external html file (there are about 30 different sections) so it can display that sections data. If I do it this way is there a way to create a header file so that all of these section can have access to the same style sheet?
You'd put your load function inside a named function and pass in an argument:
function loadStuff(divId) {
$("#testLoad").load("test.html #" + divId + '');
}
In your event handler you'd call it:
$(document).ready(function() {
loadStuff('someId');
});
You could also pass in the target ID in a similar manner.
As others have pointed out, this isn't the ideal way to do what's essentially client-side templating.
It seems like you want to be able to combine multiple different "partial" html files, and for this I would recommend you look into Angular which excels at exactly this.
Not sure why you are loading the JQuery js file the way you are. That really doesn't look safe.
Another thing you can do is create an "iffy" as some people call it where it is a script that is automatically called when the page is loaded.
<script>
(function (){
//code goes here
}())
</script>
This code will run when that page is loaded.

Page Specific JavaScript Function on Several Files of HTML

I have about 10 pages of HTML and each has a link to indexJS.js. I have a function loadMoreOnScroll() in the js file that is meant to run only for my index.html. But the loadMoreOnScroll() is run on all the pages as users scroll to the bottom.
How do I restrict loadMoreOnScroll() to only run for index.html?
Add classes to distinguish pages.
<body class="index">...
And with JavaScript:
if(document.body.className.match(/\bindex\b/)){
// code
}
of jQuery:
if($("body").hasClass("index")){
// code
}
Add a class to the body tag on the index then in javascript you can do something like
if(document.querySelector('body').className === 'myclass'){
loadMoreOnScroll();
}
Note: this assumes you have no other classes on the body. You could use a data attribute and do getAttribute('data-page') or something to similar effect.
You can just remove the loadMoreOnScroll() function from indexJS and create a new JavaSscript file with loadMoreOnScroll() in it. Be sure to include a reference to the new file in the index.html.
I'm assuming you're invoking loadMoreOnScroll from within your indexJS.js file, correct?
If so, the solution is to remove the function call from your javascript file and instead call it directly from index.html.
indexJS.js
// Create the function but don't call it here
function loadMoreOnScroll(){...}
index.html
<script src="indexJS.js></script>
<script>
// call the function
loadMoreOnScroll();
</script>
Edit:
A few other people suggested adding a body class and targeting your page that way. This approach is fine, and may work well in many scenarios but just keep in mind two things:
This works well for if you need to call your function on only one or two pages. Any more and you'll have to maintain a growing list of body classes within indexJS.js.
Using the body class as a hook decouples the function call from the page that its applies to.
In other words, the body class will have functionality tied to it that's not immediately obvious if you're only looking at the HTML. If you're working on the code yourself, you'll probably be ok, but in a team environment, it could be error-prone. (Or if you revisit the code after a few months). It all depends on the scope of your project.

AngularJS - inject trusted code from loaded content

I've hooked up a lazy loader in Angular. It pulls in full templates and extracts key information from that full template in order to populate a partial. This full page template has script tags which load in and then register with the existing app. All of this works fine. My problem is that I'd like to remove the only use of jQuery in this approach.
The root issue is that the JS inside of something.js doesn't execute when using $element.html(), but it does execute when using $.html(), despite the script tag being placed in the DOM in both approaches.
Working code, including lazy loader and post-bootstrap registration of lazy-loaded JS:
$http.get("/path/to/file.html").success(function(response) {
// response is a full HTML page including <doctype>
var partial = getOnlyWhatWeNeed(response);
// partial is now something like: '<script type="text/javascript" src="/path/to/something.js"></script><div ng-controller="somethingCtrl">{{something}}</div>'
// i'd like the following to not rely on full jQuery.
$("#stage").html(partial);
$("#stage").html($compile(partial)($scope)); // it is necessary to do it once before compile so that the <script> tags get dropped in and executed prior to compilation.
});
I've tried what seems like the logical translation:
$element.html($compile(partial)($scope));
and the DOM is created properly, but the JS inside of the loaded <script> tag doesn't actually execute. My research suggested this was an $sce issue, so I tried:
$element.html($compile($sce.trustAsHtml(partial)($scope));
but i get the same result. the DOM is fine, but the JS doesn't actually execute and so I get undefined controller issues.
I've tried playing with $sce.JS and $sce.RESOURCE_URL but the docs didnt elaborate much so I'm not sure I know whether or not what I'm trying is even right.
I've also tried $element[0].innerHTML but I get the same result as $element.html().
Preemptive disclaimer: I can trust the incoming HTML/JS. I know it's inadvisable. This isn't my baby and it is much more complicated than I explained so please try to stay on topic so other people in this position may not have as hard of a time as I am :)
The $http.get happens in a provider, and the $element.html happens in a directive. I consolidated them to remove noise from the problem.
Jquery will find any script tags and evaluate them (either a direct eval or appending them to the head for linked scripts) when calling html(), see this answer. I'm assuming angular's jquery lite doesn't do this. You would need to effectively replicate what jquery is doing and look for script tags in the html you are appending.
Something like this (although I haven't tested it):
$http.get("/path/to/file.html").success(function(response) {
// response is a full HTML page including <doctype>
var partial = getOnlyWhatWeNeed(response);
// partial is now something like: '<script type="text/javascript" src="/path/to/something.js"></script><div ng-controller="somethingCtrl">{{something}}</div>'
var d = document.createElement('div');
d.innerHTML = partial;
var scripts = d.getElementsByTagName('script');
for (var i = 0; i < scripts.length; i++) {
document.head.appendChild(scripts[0]);
}
$("#stage").html($compile(partial)($scope)); // it is necessary to do it once before compile so that the <script> tags get dropped in and executed prior to compilation.
});
This is far from an ideal solution as it gives you no guarantee of when things are loaded and doesn't really handle dependencies across scripts. If you can control the templates it would be simpler to remove the scripts from them and load them independently.

Injecting JavaScript into head element of website using Fiddler

I was thinking of using Fiddler for the following purpose...
I have a JavaScript based service I want to demonstrate to potential clients. In order to show them what their website could look like if they install (i.e. include) my script, I want to set up Fiddler on my PC, so that when fetching the client's website, the
<script type="text/JavaScript" src="myscript.js"></script>
line will be included in the HTML <head> section.
Can this be easily done with Fiddler? Could someone point me to where I may find the documentation covering that, if it is?
Thanks!
----Update----
For the time being I have resorted to using a BHO to add my script to the page. I use execScript(), upon onDocumentComplete, to run a simple piece of JavaScript which appends the .js file I need to the page. But EricLaw's pointers and jitter's answer seem like the way to go for a more complete (and elegant) way to do what I need.
If someone is interested I could upload the BHO code here.
-Thanks!
Open fiddler -> Menu Rules -> Customize Rules (or hit Ctrl+R)
The CustomRule.js file opens. Scroll down until you find the line
static function OnBeforeResponse(oSession: Session)
This is where your code goes. Here you can change the server response before the browser sees it.
The following code sample shows how to include a custom piece of jQuery code which replaces the Unanswered link in the horizontal menu with a link which serves as short cut to Unanswered jQuery Questions
I first show you the jQuery code I want to include
<script type='text/javascript'>
$(function() {
var newLink = 'Unanswered jQuery';
$('div#hmenus div.nav:first ul li:last a').replaceWith(newLink);
});
</script>
Now the fiddler code (based on code found in CustomRules.js and code samples from the FiddlerScript CookBook)
//is it a html-response and is it from stackoverflow.com
if (oSession.oResponse.headers.ExistsAndContains("Content-Type", "html") &&
oSession.HostnameIs("stackoverflow.com")) {
// Remove any compression or chunking
oSession.utilDecodeResponse();
var oBody = System.Text.Encoding.UTF8.GetString(oSession.responseBodyBytes);
// Match the jQuery script tag
var oRegEx = /(<script[^>]*jquery.min.js"><\/script>)/gi;
// replace the script tag withitself (no change) + append custom script tag
oBody = oBody.replace(oRegEx, "$1<script type='text/javascript'>$(function() {$('div#hmenus div.nav:first ul li:last a').replaceWith('Unanswered jQuery');})</script>");
// Set the response body to the changed body string
oSession.utilSetResponseBody(oBody);
}
I think you should now able to hackyourself together a piece of code which fits your problem.
Example
// Match the head end
var oRegEx = /(<\/head>)/gi;
// replace with new script
oBody = oBody.replace(oRegEx, "<script type='text/javascript' src='http://url/myscript.js'></script>$1");
if you use jQuery you can add js on the fly. I would probably think you can have a method which would include/exclude your script based on some query param. This is how you would include JS with jQuery
$.getScript('someScript.js',function(){
//Do something here after your script loads
});
Haven't tried it, but how about GreaseMonkey for IE?

How to handle localization in JavaScript files?

I want JavaScript code to be separated from views.
I got the requirement to implement localization for a simple image button generated by JavaScript:
<img src="..." onclick="..." title="Close" />
What's the best technique to localize the title of it?
PS: I found a solution by Ayende. This is the right direction.
Edit:
I got Localization helper class which provides the Controller.Resource('foo') extension method.
I am thinking about to extend it (helper) so it could return all JavaScript resources (from "ClientSideResources" subfolder in App_LocalResources) for the specified controller by its name. Then - call it in BaseController, add it to ViewData and render it in Layout.
Would that be a good idea?
EDIT
Consider writing the necessary localized resources to a JavaScript object (hash) and then using it for lookup for your dynamically created objects. I think this is better than going back to the server for translations. This is similar to adding it via viewdata, but may be a little more flexible. FWIW, I could consider the localization resources to be part of the View, not part of the controller.
In the View:
<script type="text/javascript"
src='<%= Url.Content( "~/Resources/Load?translate=Close,Open" %>'></script>
which would output something like:
var local = {};
local.Close = "Close";
local.Open = "Open";
Without arguments it would output the entire translation hash. Using arguments gives you the ability to customize it per view.
You would then use it in your JavaScript files like:
$(function(){
$('#button').click( function() {
$("<img src=... title='" + local.Close + "' />")
.appendTo("#someDiv")
.click( function() { ... } );
});
});
Actually, I'm not too fussed about keeping my JavaScript code out of my views as long as the JavaScript code is localized in a container. Typically I'll set my master page up with 4 content area: title, header, main, and scripts. Title, header, and main go where you would expect and the scripts area goes at the bottom of the body.
I put all my JavaScript includes, including any for viewusercontrols, into the scripts container. View-specific JavaScript code comes after the includes. I refactor shared code back to scripts as needed. I've thought about using a controller method to collate script includes, that is, include multiple scripts using a single request, but haven't gotten around to that, yet.
This has the advantage of keeping the JavaScript code separate for readability, but also allows me to easily inject model or view data into the JavaScript code as needed.
Actually ASP.NET Ajax has a built-in localization mechanism: Understanding ASP.NET AJAX Localization
If you insist on keeping it separate, you could do something like:
//keep all of your localised vars somewhere
var title = '{title_from_server}';
document.getElementById('someImage').title = title;
Remember, if you use JavaScript code to initialize any text of elements, your site will degrade horribly where JavaScript isn't available.

Categories

Resources