Conditional Compilation is turned off in Razor? - javascript

I've got a c# foreach loop that Is outputting some javascript to initialize some progress bars on my razor view.
#foreach (var item3 in Model)
{
#:$("#campaignMeter-#item3.ID").wijprogressbar({ value: #((item3.TotalRedeemed / item3.TotalSold) * 100), fillDirection: "east" });
}
The problem I'm having is visual studio is reporting "Conditional Compilation is Turned Off" on the foreach loop, and the small calculation for value is always coming out as 0, despite TotalRedeemed and TotalSold having values. Am I using the #: operator properly? Thanks for your help.
I've tried both suggestions so far and this is what I currently have:
#foreach (var item3 in Model)
{
var percentage = (item3.TotalRedeemed / item3.TotalSold) * 100;
<text>$("#campaignMeter-#item3.ID").wijprogressbar({ value: #percentage, fillDirection: "east" });</text>
}
percentage is coming out as 0, but TotalRedeemed and TotalSold have values, as they are printed on the view before this is called. Is there a way to set a break point on my view to see what percentage is before its printed?

Timmi4sa - I agree, there isn't much of an answer as to why we are getting this error. I finally got a step closer to understanding it all so I thought i would share.
Conditional Compilation is defined my MS as this:
Conditional compilation enables JScript to use new language features
without sacrificing compatibility with older versions that do not
support the features. Some typical uses for conditional compilation
include using new features in JScript, embedding debugging support
into a script, and tracing code execution.
From what I can tell, we are really talking about a feature of VS. My current guess is this: VS lets you debug JS, but it has to know what the JS is in order to debug it. By default Conditional Compilation is off - I am guessing that there is some additional overhead involved. What we are doing when we are using #Model... in JS is doing exactly what the warning states (more or less) - creating conditional JS. The JS ends up being different things depending on the value of our C#/VB variables.
According to MS the solution is to turn Conditional Compilation on as mentioned above via the statement:
/*#cc_on #*/
While I tend to be a bit anal and prefer to avoid warnings, this may be one I just simply ignore (unless someone can educate me further as to why this is a bad idea).
If you really want the error to go away and do not like the Conditional Compilation flag, you can wrap the C#/VB code call in double quotes like below. But this feels dirty and only works because JS is loosely typed... (well with numeric types anyway, strings shouldn't have a problem... regardless, this feels hacky)
"#Model.Items.Count()"
Edit: I went and did a little more research... I like the idea of CC even less after skimming this article: http://www.javascriptkit.com/javatutors/conditionalcompile.shtml. I think I will just be ignoring this warning.
I hope that helps explain away some of the mystery.
EDIT :
Another option is to throw a HiddenFor down on the form, give it an Id and then populate a JS variable from that field (jQuery makes this pretty easy). This is what I ended up doing for the time being. It eliminates warnings and I often want to compare the JS variable back to the original VMC field anyway. For those of you who need it:
#* Somewhere in your form - assuming a strongly typed view *#
#Html.HiddenFor(x => x.YourField, new { id = "SomethingMeaningful" })
// and then in your JS
$(document).ready(function(){
...
var jsYourField = $("#SomethingMeaningful").val();
...
});
Please note that JS variable and MVC variables do not always 'line up' exactly right so you may need to do some casting or additional work when you copy the variable value into your JS.

Add /*#cc_on #*/ in your code.
Update: Found out why they could be 0:
item3.TotalRedeemed and item3.TotalSold need to be float or double. If they are int, it comes out to 0.

Try this:
#foreach (var item3 in Model)
{
<text>$("#campaignMeter-#item3.ID").wijprogressbar({
value: #((item2.TotalRedeemed / item2.TotalSold) * 100),
fillDirection: "east"
});</text>
}
But a better approach would be to perform this calculation on a view model property, so that your view looks like this:
#foreach (var item in Model)
{
<text>$('#campaignMeter-#(item.ID)').wijprogressbar({
value: #item.SoldPercentage,
fillDirection: "east"
});</text>
}

I thought I would share what worked for me,
I had this same issue : System.Web.HttpCompileException (0x80004005)
below the exception I get: The name 'Url' does not exist
When I looked at the View I noticed the only place that was using Url was the razor code #Url.
This post talked about the references to razor and MVC.
When i looked in the Views folder in the solution there was a web.config file that contained all the references however it was renamed web.src.config. As soon as I changed it to web.config I was up and running again.

Related

Object has no method 'charAt' in jQuery plugin

I am attempting to use the autoNumeric jQuery plug-in which helps with the conversion of various currencies in jQuery.
The plug-in itself works when I use it in a jsFiddle example.
$(function () {
$('.money').autoNumeric('init', {
aSign: '$',
vMin: '-999999999.99',
nBracket: '(,)'
});
});
However, as soon as I integrate it into a big, legacy project, I start receiving the above error on line 194. I know why I'm getting the error - a string is not being passed into the negativeBracket function (negativeBracket(s, nBracket, oEvent) is the signature). Instead, it seems to be a jQuery object - e.fn.init1. I'm confused on how this might be happening. I realize the community may not be able to give a direct answer, but I would love (and will accept as an answer) being pointed in the right direction as nothing has jumped out at me so far.
Update
So, have some additional info that may be of help. It still has me stumped how it's happening (unfortunately, the answers below didn't help to provide any additional insight). When I link in autoNumeric, I key it off of any text field with the class money. It does work as I am typing in the box. I can see see formatting. However, when I tab into a new box, the box I just finished typing in clears itself completely after hitting line 152 in autoNumeric with the same exact error.
#Carlos487 was correct in his answer when he said I have an object that is not a string. I instead have an object that, I believe, is a function. Here's what I'm seeing in Chrome debugger tools:
e.fn.init[1]
> 0: input#price.money required
> context: input#price.money required
length: 1
selector: ""
> __proto__: Object[0]
The "arrowed" items can be further expanded out. I don't know if this provides any more clues, but it's at least something a bit different.
The errors like
no method XXXXX in Object
are produced because you are trying to call obj.XXXX() and obj is not of the desired type, in your particular case a string.
Have you tried in another browser because older or IE can be a little troublesome. I would recomend using chrome developer tools with your legacy app to see if anything else is conflicting or producing the error
I will bet money that you are using a second library which is interfering with jQuery. It has probably overridden $ with its own function.
Try using jQuery instead of $:
jQuery(function () {
jQuery('.money').autoNumeric('init', {
aSign: '$',
vMin: '-999999999.99',
nBracket: '(,)'
});
});
It turns out that the issue was a myriad of issue compounding into the error I saw. A couple things that was happening:
The validator plug-in was wrapping the jQuery object in its own structure (hence the charAt issue).
Once I fixed that, I also learned that some homegrown code was also wiping and rewriting data into the field to provide formatting (which is what autoNumeric is also doing), so autoNumeric would bomb out because it would get a null value and attempt to format it.
There was some other random craziness that also needed cleaned up. So...issue resolved! Still more to work on, but at least this hurdle is past. Thanks all for your help.

Simple way to check/validate javascript syntax

I have some big set of different javascript-snippets (several thousands), and some of them have some stupid errors in syntax (like unmatching braces/quotes, HTML inside javascript, typos in variable names).
I need a simple way to check JS syntax. I've tried JSLint but it send too many warnings about style, way of variable definitions, etc. (even if i turn off all flags). I don't need to find out style problems, or improve javascript quality, i just need to find obvious syntax errors. Of course i can simply check it in browser/browser console, but i need to do it automatically as the number of that snippets is big.
Add:
JSLint/JSHint reports a lot of problems in the lines that are not 'beauty' but working (i.e. have some potential problems), and can't see the real problems, where the normal compiler will simply report syntax error and stop execution. For example, try to JSLint that code, which has syntax errors on line 4 (unmatched quotes), line 6 (comma required), and line 9 (unexpected <script>).
document.write('something');
a = 0;
if (window.location == 'http://google.com') a = 1;
document.write("aaa='andh"+a+"eded"');
a = {
something: ['a']
something2: ['a']
};
<script>
a = 1;
You could try JSHint, which is less verbose.
Just in case anyone is still looking you could try Esprima,
It only checks syntax, nothing else.
I've found that SpiderMonkey has ability to compile script without executing it, and if compilation failed - it prints error.
So i just created small wrapper for SpiderMonkey
sub checkjs {
my $js = shift;
my ( $js_fh, $js_tmpfile ) = File::Temp::tempfile( 'XXXXXXXXXXXX', EXLOCK => 0, UNLINK => 1, TMPDIR => 1 );
$| = 1;
print $js_fh $js;
close $js_fh;
return qx(js -C -f $js_tmpfile 2>&1);
}
And javascriptlint.com also deals very good in my case. (Thanks to #rajeshkakawat).
Lots of options if you have an exhaustive list of the JSLint errors you do want to capture.
JSLint's code is actually quite good and fairly easy to understand (I'm assuming you already know JavaScript fairly well from your question). You could hack it to only check what you want and to continue no matter how many errors it finds.
You could also write something quickly in Node.js to use JSLint as-is to check every file/snippet quickly and output only those errors you care about.
Just use node --check filename
Semantic Designs' (my company) JavaScript formatter read JS files and formats them. You don't want the formatting part.
To read the files it will format, it uses a full JavaScript parser, which does a complete syntax check (even inside regular expressions). If you run it and simply ignore the formatted result, you get a syntax checker.
You can give it big list of files and it will format all of them. You could use this to batch-check your large set. (If there are any syntax errors, it returns a nonzero error status to a shell).

JSLint "eval is evil." alternatives

I am have some JavaScript functions that run on both the client (browser) and the server (within a Java Rhino context). These are small functions - basically little validators that are well defined and don't rely upon globals or closures - self-contained and portable.
Here's an example:
function validPhoneFormat(fullObject, value, params, property) {
var phonePattern = /^\+?([0-9\- \(\)])*$/;
if (value && value.length && !phonePattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
To keep things DRY, my server code gets a handle on each of these functions and calls toString() on them, returning them to the browser as part of a JSON object. Something like this:
{ "name" : "phoneNumber",
"policies" : [
{ "policyFunction" : "\nfunction validPhoneFormat(fullObject, value, params, property) {\n var phonePattern = /^\\+?([0-9\\- \\(\\)])*$/;\n if (value && value.length && !phonePattern.test(value)) {\n return [{\"policyRequirement\":\"VALID_PHONE_FORMAT\"}];\n } else {\n return [];\n }\n}\n"
}
]
}
My browser JS code then takes this response and creates an instance of this function in that context, like so:
eval("var policyFunction = " + this.policies[j].policyFunction);
policyFailures = policyFunction.call(this, form2js(this.input.closest("form")[0]), this.input.val(), params, this.property.name));
This all works very well. However, I then run this code through JSLint, and I get back this message:
[ERROR] ValidatorsManager.js:142:37:eval is evil.
I appreciate that often, eval can be dangerous. However, I have no idea how else I could implement such a mechanism without using it. Is there any way I can do this and also pass through the JSLint validator?
I wouldn't worry about it since you are only passing these function strings from the server to the client, and are thus in control of what will be evaluated.
On the other hand, if you were going the other direction and doing the evals of client-passed code on the server, that would be an entirely different story...
Update:
As disabling the validation option in your comment may cause you to miss future errors, I would instead suggest passing the function name rather than the entire function and have the function library mirrored on the server and client. Thus, to call the function, you'd use the following code:
var policyFunction = YourLibraryName[this.policies[j].policyFunctionName];
var policyArguments = this.policies[j].policyArguments;
policyFunction.apply(this, policyArguments);
Update 2:
I was able to validate the following code with JSLint successfully, which essentially allows you to "turn off" validation for the vast minority of cases where eval is appropriate. At the same time, JSLint still validates normal eval calls, and all uses of this method should throw up flags for future developers to avoid using it/refactor it out where possible/as time allows.
var EVAL_IS_BAD__AVOID_THIS = eval;
EVAL_IS_BAD__AVOID_THIS(<yourString>);
Dont encode a function as a string in JSON. JSON is for content, which you are confounding with behavior.
Instead, I suppose you could return JS files instead, which allow real functions:
{ name : "phoneNumber",
policies : [
{ policyFunction : function() {
whateverYouNeed('here');
}
}
]
}
But while that solves the technical issue, it's still not a great idea.
The real solution here is to move your logic out of your content entirely. Import a JS file full of little validation functions and call them as needed based on a dataType property in your JSON or something. If this functions are as small and portable as you say, this should be trivial to accomplish.
Getting your data all tangled up with your code usually leads to pain. You should statically include your JS, then dynamically request/import/query for your JSON data to run through your statically included code.
I would avoid using eval in all situations. There's no reason you can't code around it. Instead of sending code to the client, just keep it hosted on the server in one contained script file.
If that's not doable, you can also have a dynamically generated javascript file then pass in the necessary parameters via the response, and then dynamically load the script on the client side. There's really no reason to use eval.
Hope that helps.
You can use
setInterval("code to be evaluated", 0);
Internally, if you pass setInterval a string it performs a function similar to eval().
However, I wouldn't worry about it. If you KNOW eval() is evil, and take appropriate precautions, it's not really a problem. Eval is similar to GoTo; you just have to be careful and aware of what you're doing to use them properly.
With very little parsing you could have had it like so:
var body = this.policies[j].policyFunction.substr;
body = body.substr(body.indexOf("(") + 1);
var arglist = body.substr(1, body.indexOf(")"));
body = body.substr(arglist.length + 1);
var policyFunction = new Function(arglist, body);
Which would provide a bit of validation, avoid the literal use of eval and work synchronously with the code. But it is surely eval in disguise, and it is prone to XSS attack. If the malevolent person can get their code loaded and evaluated this way - it will not save you. So, really, just don't do it. Add a <script> tag with the proper URL and that would be certainly safer. Well, you know, better safe then sorry.
PS. My apologises if the code above doesn't work, it only shows the intent, I've not tested it, and if I made a mistake at counting parenthesis or some such - well, you should get the idea, I'm not advertising it by any means.
DRY is definitely something I agree with, however there is a point where copy+pasting is more efficient and easy to maintain than referencing the same piece of code.
The code you're saving yourself from writing seems to be equivalent to a clean interface, and simple boiler plate. If the same code is being used on both the server and the client, you could simply pass around the common pieces of the function, rather than the whole function.
Payload:
{
"name": "phoneNumber",
"type": "regexCheck",
"checkData": "/^\\+?([0-9\\- \\(\\)])*$/"
}
if(payload.type === "regexCheck"){
const result = validPhoneFormat(fullObject, value, payload.checkData)
}
function validPhoneFormat(fullObject, value, regexPattern) {
if (value && value.length && !regexPattern.test(value))
return [ {"policyRequirement": "VALID_PHONE_FORMAT"}];
else
return [];
}
This would give you the ability to update the regex from a single location. If the interface changes it does need to be updated in 2 places, but I wouldn't consider that a bad thing. If the client is running code, why hide the structure?
If you really, really want to keep both the object structure and the patterns in one place - extract it to a single API. Have a "ValidatePhoneViaRegex" api endpoint which is called by all places you'd be passing this serialized function to.
If all of this seems like too much effort, set jslint to ignore your piece of code:
"In JSHint 1.0.0 and above you have the ability to ignore any warning with a special option syntax. The identifier of this warning is W061. This means you can tell JSHint to not issue this warning with the /*jshint -W061 */ directive.
In ESLint the rule that generates this warning is named no-eval. You can disable it by setting it to 0, or enable it by setting it to 1."
https://github.com/jamesallardice/jslint-error-explanations/blob/master/message-articles/eval.md
I would prefer to see copy+pasted code, a common api, or receiving parameters and copy+pasted boiler plate than magical functions passed in from the server to be executed.
What happens if you get a cross-browser compatibility error with one of these shared functions?
Well, the first thing to bear in mind is that jsLint does make the point that "it will hurt your feelings". It's designed to point out where you're not following best practices -- but code that isn't perfect can still work just fine; there's no compulsion upon you to follow jsLint's advice.
Having said that, eval is evil, and in virtually all cases there is always a way around using it.
In this case, you could use a library such as require.js, yepnope.js or some other library that is designed to load a script separately. This would allow you to include the javascript functions you need dynamically but without having to eval() them.
There are probably several other solutions as well, but that was the first one that came to my mind.
Hope that helps.

Razor/JavaScript and trailing semicolon

Using Visual Studio 2012, on a Razor view page, in the JavaScript section, I am getting what I think is a battle between Razor syntax vs JavaScript syntax. In particular, the trailing semicolon in the script section is flagged by intellisense and a compiler warning (not error) is delivered:
'Warning 13 Syntax error'.
If I remove it, then I get a statement termination recommendation (ReSharper in this case, but just good practice).
<script type="text/javascript">
$().ready(function(){
var customer = #Html.Raw(ViewBag.CustomerJSON); // <- Razor (I think) doesn't like this semicolon
});
</script>
Is this a bug in Razor? If so, is there a way I can rewrite this to avoid this issue?
Is this a bug in Razor?
Absolutely not. Run your application, and it will work as expected.
It is a bug in the tools you are using (Visual Studio 2012, ReSharper, ...) that are incapable of recognizing perfectly valid syntax and warning you about something that you shouldn't be warned about. You could try opening an issue on the Microsoft Connect site and signalling this bug if that hasn't already been done.
Since this still seems to be happening and it is a nuisance I figured I will at least let others know what I ended up using as a "hack". I don't want to ignore the warning and would rather accept a hokier syntax (and yes someone is going to say this will kill performance :))
What I use as a workaround is to use a client side addition at the end. For me this error occurred on defining an "integer" constant, so
window.foo = #(Model.Something);
gave me the good old semicolon error. I simply changed this to:
window.foo = #Model.Something + 0;
(In the stated questions case you should just be able to add '', so + ''.
I know there is a whole another addition happening on the client and it isn't elegant, but it does avoid the error. So use it or don't, but I prefer this over seeing the warning/error.
If someone knows of a server-side syntactical workaround for this I would prefer this to the client-side one, so please add.
I found that wrapping the Razor syntax in a JavaScript identity function also makes the IDE happy.
<script type="text/javascript">
#* I stands for Identity *#
function I(obj) { return obj; }
$().ready(function(){
var customer = I(#Html.Raw(ViewBag.CustomerJSON));
});
</script>
This worked for me:
var customer = #Html.Raw(ViewBag.CustomerJSON + ";")
Here's a workaround for booleans:
var myBool = #(Model.MyBool ? "true;" : "false;")
This worked for me
#Html.Raw(string.Format("var customer = {0};", ViewBag.CustomerJSON));
<script type="text/javascript">
$().ready(function(){
var customerName = ('#ViewBag.CustomerName'); // <- wrap in parens
});
</script>
Isn't it as simple as wrapping in parentheses? Putting values through the console seem to work fine with no side effect.
It works for strings, but it still gives the error for non-quoted values, but I still like this for string values. For numbers you could just use parseInt('#Model.TotalResultCount', 10).

ASP.NET inline server tags

I'd like to start by saying that my code is working perfectly, this is more a "how best to do it" kind of question.
So I have code like this in my .aspx file:
function EditRelationship() {
var projects=<%= GetProjectsForEditRelationship() %>;
// fill in the projects list
$('#erProjectsSelect').empty();
for(var i in projects)
$('#erProjectsSelect').append('<option value='+projects[i][0]+'>'+projects[i][1]+'</option>');
var rels=<%= GetRelationshipsForEditRelationship() %>;
// etc
}
Again, it's working fine. The problem is that VS2008 kinda chokes on code like this, it's underlining the < character in the tags (with associated warnings), then refusing to provide code completion for the rest of the javascript. It's also refusing to format my document anymore, giving parsing errors. The last part is my worst annoyance.
I could put some of these in evals I guess, but it seems sorta dumb to add additional layers and runtime performance hits just to shut VS up, and it's not always an option (I can't remember off the top of my head where this wasn't an option but trust me I had a weird construct).
So my question is, how do you best write this (where best means fewest VS complaints)? Neither eval nor ajax calls fit this imo.
If your aim is to reduce VS complaints, and if you are running asp.net 4 (supporting Static client Ids), maybe a strategy like the following would be better?
Create a ASP:HiddenField control, set its ClientIdMode to "Static"
Assign the value of GetRelationshipsForEditRelationship() to this field on page load
In your javascript, read the value from the hidden field instead, I assume you know how to do this.
It's more work than your solution, and you will add some data to the postback (if you perform any) but it won't cause any VS complaints I guess :)
You could do this from your page in the code-behind
ClientScript.RegisterArrayDeclaration("projects", "1, 2, 3, 4");
or to construct something like JSON you could write it out
ClientScript.RegisterClientScriptBlock(GetType(), "JSONDeclarations", "your json stuff");
UPDATE Based on my comment
<script id="declaration" type="text/javascript">
var projects=<%= GetProjectsForEditRelationship() %>;
var rels=<%= GetRelationshipsForEditRelationship() %>;
</script>
<script type="text/javascript">
function EditRelationship() {
// fill in the projects list
$('#erProjectsSelect').empty();
for(var i in projects)
$('#erProjectsSelect').append('<option value='+projects[i][0]+'>'+projects[i][1]+'</option>');
}
</script>
I don't have VS2008 installed to test with, so take this with a grain of salt, but have you tried something like this?
var projects = (<%= GetProjectsForEditRelationship() %>);
Something like that might trick the JavaScript parser into ignoring the content of your expression.
For what it's worth, VS2010 correctly parses and highlights your original code snippet.
Is it an option to move this to VS2010? I just copied and pasted your code and the IDE interpreted it correctly.
The best solution is to put javascript in a separate file and avoid this entirely. For this particular function, you're doing server-side work. Why not build the list of options that you intend to add dynamically in codebehind, put them in a hidden div, and then just have jQuery add them from the already-rendered HTML?
If you have a situation where you really want to dynamically create a lot javascript this way, consider using ScriptManager in codebehind to set up the variables you'll need as scripts and register them, then your inline script won't need to escape
ScriptManager.RegisterClientScript("projects = " + GetProductsForEditRelationship());
(Basically, that is not the complete syntax, which is context dependent). Then refer to "projects" in your function.
(edit)
A little cleaner way to do this on a larger scale, set up everything you need like this in codebehind:
string script = "var servervars = {" +
"GetProductsForEditRelationship: " + GetProductsForEditRelationship() +
"GetRelationshipsForEditRelationship: " + GetRelationshipsForEditRelationship() +
"}"
and refer to everything like:
servervars.GetProductsForEditRelationship
If you do this a lot, of course, you can create a class to automate the construction of the script.

Categories

Resources