Is it possible to use razor syntax in Javascript files? - asp.net-mvc-3

I'd like to use razor syntax inside my Javascript files. Is this possible without including the javascript inline into the page?

I found a razor engine RazorJS on nuget that solves # in js files
The owner blog and explanations about the package abilities
The Nuget package
see more in this question

The Razor engine only runs against the page, not any included javascript files.
You could write a custom parser that will run the view engine against any javascript files before serving them, and I imagine any attempt to do so would be a very useful open source project.
However, the simplest solution that comes to mind (if these variables are not sematically linked to any DOM elements) is to simply declare and initialise your variables in the page (or in an included partial page) and your javascript (in .js files) relies on these variables being defined.
If however the variables that you require are logically associated with DOM elements, I prefer to use data-* attributes to define these, this way your javascript can be consumed by the html, rather than the other way around. For example, if you have a content area that should be automatically updated by javascript (using jQuery as an example here):
HTML:
<div data-auto-refresh="pathToContent" data-auto-refresh-milliseconds="1000"></div>
Javascript:
$(function() {
$('[data-auto-refresh]').each(function() {
var self = $(this);
var url = self.data('auto-refresh');
var interval = self.data('auto-refresh-milliseconds');
// Code to handle refresh here ...
});
});

You can set the value in hidden field in yout cshtml file , and then in your javascript files you can access the hidden field.

Related

Change CSS on AJAX request in Wicket

I have a component A that should dynamically change the font size of some of it's contents. I currently use CSS variables to do that and the component will contribute some CSS String containing these CSS variables:
public void renderHead(IHeaderResponse response) {
String fontCss = // dynamically fetch CSS cariables
response.render(CssHeaderItem.forCSS(fontCss, "font-css"));
}
On the same page I have the possibility to change these font sizes using an AJAX update within another component B. This will add the component A to the AjaxRequestTarget, which will cause the renderHead method to be executed with updated values for the font CSS variables.
However, I don't see an updated font size in my browser as the old CSS variables still seem to be present. How can I enforce the new CSS to overwrite the old one?
So far I found 2 solutions, that seem like dirty workarounds to me:
Add the whole page to the AjaxRequestTarget, so the whole page will be refreshed.
Add JavaScript to the AJAX update to remove the old styling with:
var allStyles = document.getElementsByTagName("style");
for (var style of allStyles) {
if (style.getAttribute("id").includes("font-css")) {
style.remove();
}
}
Is there a cleaner solution to this problem?
You found the problem with workaround 2.
response.render(CssHeaderItem.forCSS(fontCss, "font-css"));
adds <style id="font-css"> ... </style> to the page. Later when the Ajax response contributes the new content the JavaScript logic finds that there is an HTML element with id font-css and assumes that there is nothing to do.
A simple solution is to use dynamic id, e.g. by using UUID in #renderHead().
Another solution is to make this <style> a proper Wicket Component, a Label, that could be added to the AjaxRequestTarget with an updated Model when needed.

Reload javascript after thymeleaf fragment render

I have javascript files defined in the <head> of both my layout decorator template and my individual pages which are decorated. When I update a thymeleaf fragment in one of my pages the javascript defined in the head of the parent page no longer works. Is there a standard way to 'refresh' these js files?
Thanks.
Additional clarification :
I have a form submitted by an ajax call which updates a table in the page. I have a Jquery onClick function targeting a button in the updated table. The javascript doesn't seem able to bind to the returned elements in the updated part of the page. I select by element class and can see that the selection works prior to the partial fragment render.
For me it is unclear what you mean by
javascript defined in the head of the parent page no longer works.
The page is created on the server. Normally it contains urls of the javascript files
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
In this case 'refreshing' the javascript files can happen only in the client.
Check the html of the page in the client.
Are the tags as expected ?
Are there tags for all expected javascript files ?
With the browser tools (for example Google Chrom developer tools ) check that all script files are actually loaded.
If this doesnt help, it could be that the order of the script tags has changed between the first and second load. This could cause a different behaviour of the javascript executed in the browser.
EDIT :
With the initial load you bind javascript callbacks to dom elements.
You do this directly or through Jquery or other libraries.
When a new dom element is loaded, it has no callbacks bound to it, even if it has the same id as a replaced dom element.
So after the load you have to bind your callbacks again.
If you bound them 'by hand', just bind it again.
If you are using a JQuery plugin, that made the bindings, look into the code or documentation, many of them have a function for that or you can call initialization again.
Once you added new content to the DOM you need to bind again the new content.
Let's say I have a button with some class, the event in binded to the class:
<button class="someclass">Button 1</button>
<script>
var something = function() {
// do something
};
$(".someclass").on("click", something);
</script>
If I add more buttons from the same class to the DOM, they will have not have the click event binded. So once you load the new content via ajax, also remove all binding and add again (you need to remove or you will have buttons with 2 events).
$(".someclass").off("click");
$(".someclass").on("click" , something);

How do I add DOM elements in jasmine tests without using external html files?

I'm writing some simple jasmine tests and I'm getting an exception since the code I'm testing is looking for a form that doesn't exist because there's no DOM when testing a js file only: $("form")[0] in the tested js file leads to:
TypeError: $(...)[0] is undefined
I read a bit about jasmine-jquery and realized I can use some html fixture with an external html file. That flow seems quite messy, since all I need to do is only to add an empty valid form so that the test (which focusing on something else) will run, something like <form></form> appending would be enough I think.
At first I thought that sandbox() function will be the solution, but it seems that it creates only divs, and I need a form.
Any simple way to add some elements by using only code in jasmine spec file?
The simplest solution is to add the form to the DOM by yourself in the before block and then delete it in the after block:
describe(function(){
var form;
beforeEach(function(){
form = $('<form>');
$(document.body).append(form);
});
it('your test', function(){
})
afterEach(function(){
form.remove();
form = null;
});
});
Also writing your sandbox helper isn't that hard:
function sandbox(html){
var el;
beforeEach(function(){
el = $(html);
$(document.body).append(el);
});
afterEach(function(){
el.remove();
el = null;
});
Another approach is to use jasmine fixture
The concept
Here's one way to think about it:
In jQuery, you give $() a CSS selector and it finds elements on the
DOM.
In jasmine-fixture, you give affix() a CSS selector and it adds those
elements to the DOM.
This is very useful for tests, because it means that after setting up
the state of the DOM with affix, your subject code under test will
have the elements it needs to do its work.
Finally, jasmine-fixture will help you avoid test pollution by tidying
up and remove everything you affix to the DOM after each spec runs.
See also: SO: dom manipulation in Jasmine test
You should use sandbox() to create a div and create a form element and append to sandbox, this is the safer way to jasmine take control to this fixtures in the DOM.

Telerik().ScriptRegistrar() How to prevent loading jquery libraries?

Script registrar loads jquery.validation.min.js even after
Html.Telerik().ScriptRegistrar().jQuery(false)
Is there any way to tell it not to do so?
Even when I try to load exactly what I need, doing this:
#Html.Telerik().ScriptRegistrar().jQuery(false).DefaultGroup(g =>
{
g.Add("telerik.common.min.js");
g.Add("telerik.tabstrip.min.js");
}
And if for example I have a telerik grid on the page it would load all necessary scripts including grid.min, grid.editing and jquery.validate.min.
I prefer to control it myself and instead of that simply to get an error, or non-functioning elements if I forgot to define the right scripts.
If I try to use this snippet:
#Html.Telerik().ScriptRegistrar().jQuery(false).Scripts(s =>
{
s.Add("telerik.common.min.js");
...
It ignores useTelerikContentDeliveryNetwork="true" in web.config, and searches for scripts on local server. I still want to use CDN.
UPD: Is there actually a way to use telerik's CDN sources but if for some reason they are down, load all the stuff from the project's server?
As a further update to this answer for people coming from search engines: You can now remove jQuery Validation in addtion to jQuery by using something like:
#Html.Telerik().ScriptRegistrar().jQuery(false).jQueryValidation(false)
.jQuery(false) indeed prevents including of jquery.js only. It does not affect jquery.validate.js and was never meant to. Currently there is no way to stop the ScriptRegistrar from including jquery.validate.js when there is an editable grid in the page.
There is no built-in support for fallback when you are using the Telerik CDN. A manual workaround can be implemented though. Something like this:
#(Html.Telerik().ScriptRegistrar())
<script type="text/javascript">
if (typeof jQuery === "undefined" || typeof $.telerik === "undefined") {
// the CDN failed for some reason use local files
document.write("<script src='scripts/telerik.common.min.js'><\/script>");
document.write("<script src='scripts/telerik.grid.min.js'><\/script>");
// etc
}
</script>

Create base jqgrid

I have a website with several views, and most of them have a jqGrid on them.
I'd like to set some base options on all my jqgrids. For example, I'd like the view option to always be set to true, and the search option to always be set to false.
Additionally, there are several that I'd like to have the same button labels.
Is there any way to do this with a jqGrid?
Look at the answer which shows how to set default settings jQuery.jgrid.nav. In your case it would be
jQuery.extend(jQuery.jgrid.nav,
{search:false,view:true, viewtext:"View label", viewtitle:"View tooltip"}
);
Other default settings you can change in the same way using jQuery.jgrid.del, jQuery.jgrid.view and of course jQuery.jgrid.defaults.
You don't need to place the code inside of jQuery(document).ready(function() {/**/});. It is enough just ecxecute the code like jQuery.extend(jQuery.jgrid.nav, {search:false,view:true}); inside a JavaScript file loaded after the jquery.jqGrid.min.js.
You could add an additional script tag to your HTML that references a JS file with some base configuration stuff for the grid in a $().ready(function() {}); block.
You could also create a base configuration function or variable that you store in that external JS, and reference that configuration on each view page.
I would prefer to write the base function, and not the ready event handler as the ready handler will NOT run at a predictable time. You won't know if it properly ran before your jqGrid configure function ran.

Resources