MVC Model property not updated when accessed in javascript - javascript

I have this in my cshtml file:
#for (var i = 0; i < Model.Vehicles.Count; i++){
#Html.CheckBoxFor(m => Model.Vehicles[i].Selected)}
Basically Model.Vehicles is a List of vehicles and the Selected property is a bool...
I have a button that when clicked, calls this function:
function delSel(){
var vehicles = '#Html.Raw(Json.Encode(Model.Vehicles))';
var selIDs = "";
for(var i = 0; i < vehicles.length; i ++)
{
if (vehicles[i].Selected == "true") {
selIDs = selIDs + vehicles[i].ID + ",";
}
}
document.getElementById('CRVehicleIDs').value = selIDs;
}
My problem is, eventhough the Checkbox is checked, the value of the Selected property is always equal to false... Is there a better way to get the selected items in this case?

var vehicles = '#Html.Raw(Json.Encode(Model.Vehicles))';
This will not work as you are expecting, the razor syntax is rendered server side which means the value of this will not get updated when a user clicks on the checkboxes.
What you can do however is when you create you're checkboxes, give them an ID using i variable in your for loop.
#Html.CheckBoxFor(m => Model.Vehicles[i].Selected, new { id = "checkbx_" + i })
Then you can iterate through your checkboxes with a for loop.
function delSel(){
var vehicles = #Html.Raw(Json.Encode(Model.Vehicles));
var selIDs = "";
for(var i = 0; i < vehicles.length; i ++)
{
if (document.getElementById('checkbx_' + i).checked) {
selIDs = selIDs + vehicles[i].ID + ",";
}
}
document.getElementById('CRVehicleIDs').value = selIDs;
}

You're rendering this.Model.Vehicles to JSON which is then rendered within Javascript single-quotes - this will likely result in invalid Javascript syntax when accessed in a browser because JSON object property names are also enclosed in quotes.
Remove the quotes around #Html.Raw.
You would have spotted this if you looked at the rendered HTML of the page and saw that a large chunk of it would be covered in syntax errors.
Other tips:
JavaScript is typically styled with the opening brace on the same line as the keyword (as with Java), not the line below (as C#). It's also customary to use camelCase for JavaScript objects, not TitleCase. You should be able to customize your JSON-generator to use camelCase, refer to the documentation.
Boolean properties tend to be prefixed with Is, so it would be IsSelected (or isSelected in camelCase).
This is suboptimal:
if( vehicles[i].Selected == "true" ) {
Assuming that the Selected property is rendered as Javascript boolean value, you need only act on it directly:
if( vehicles[i].Selected ) {

Related

Value of variable changing over time inside function w/o reassignment

<script>
document
.getElementById('country')
.addEventListener('change', function() {
'use strict';
var value1 = this.value;
console.log(value1);
var vis = document.querySelectorAll('.input-group-addon'),
country = document.getElementsByClassName(value1);
console.log(country.length);
// Point One
var i;
if (vis !== null) {
for (i = 0; i < vis.length; i++)
vis[i].className = 'input-group-addon inv';
console.log(country.length);
// Point Two
}
if (country !== null) {
for (i = 0; i < country.length; i++) {
country[i].className = 'input-group-addon';
// Point Three
}
}
});
</script>
This has been bothering me for a while now. I am trying to get the value of a selected value in
document.querySelectorAll('.input-group-addon')
and find matching class names in
document.getElementsByClassName(value1)
The nodelist of country is available at Point One and changes to null at Point Two.
Is there a basic logic or syntax error in my code?
and changes to null at Point Two
I assume you mean that the list is empty. The variable should not magically become null.
getElementsByClassName returns a live HTMLCollection. Meaning it will always reflect the current state of document. If you change the class name of an element, it will automatically either be added or removed from the collection.
If you don't want that, then either use querySelectorAll, which returns a collection that is not live, or convert the collection to an array.

Refer to an array using a variable

I am writing a page that collects serial numbers for parts installed in an assembly. I want to validate the user input on the client-side, if I can.
So if I have multiple dense arrarys, how can I refer to them using a varaiable? For instance, say I have three densely packed arrays who's names represent part numbers, and who's values represent serial numbers (that have been consumed in other assemblies).
arr_PN-123-ABC = ('SN0123','SN0124','SN0125')
arr_PN-456-DEF = ('SN00333','SN00334','SN00335')
arr_PN-789-GHI = ('SN-0001','SN-0002','SN-0003','SN-0004')
function fcnValidateSN(_givenPN, _givenSN) {
//make sure the given values are not null or empty...
//derive the array of serial numbers that coorsponds to the given part number...
var vArrName = "arr_" + vGivenPN;
//loop thru the array of serial numbers to determine if the given sn was already used...
for(var x=0; x < vArrName.length(); x++) {
if(vArrName[x]==_givenSN) {
alert("Serial number '" + _givenSN + "' was already used in another assembly.");
theForm.txtPN.focus();
return;
}
} //end 'for' loop
} //end fcnValidateSN()
So the problem is that 'vArrName' is a string with a value of 'arr_' instead of a refernece to an array who's name is 'arr_'.
I tried wrapping it with the eval() function, but eval() treats dashes as minus signs.
One other note: I cannot use jquery for this effort.
Thank you
You cannot generate a reference to a variable declared with var (except see below). You can use dynamic property names to refer to properties of objects, so:
var arrays = {
"arr_PN-123-ABC": ['SN0123','SN0124','SN0125'],
"arr_PN-456-DEF": ['SN00333','SN00334','SN00335'],
// ...
};
Then:
console.log( arrays["arr_PN-" + num + "ABC"][0] ); // SN0123
Note that you cannot use "-" in a variable name, but you can use it in an object property name.
The exception to not being able to access var variables by dynamic name is made for global variables in a browser. Those variables all end up as properties of the window object.
An array in JavaScript is delimitated by [ and ], not ( or ).
A valid JavaScript variable name can't contain '-'
The length property of an array isn't a function
Well, I've done some (actually, a lot of) adjustments in your code, but I think this is what you need:
var serialGroups = {
PN_123_ABC: ['SN0123','SN0124','SN0125'],
PN_456_DEF: ['SN00333','SN00334','SN00335'],
PN_789_GHI: ['SN-0001','SN-0002','SN-0003','SN-0004']
};
function validateSerial(groupName, sn) {
var serials = serialGroups[groupName];
for(var i=0; i < serials.length; i++){
if(serials[i] == sn) {
alert("Serial number '" + sn + "' was already used in another assembly.");
//Do whatever you want here
return;
}
}
}
Use a single object that has the arrays as elements:
var arr_PN = {
'123-ABC': ('SN0123','SN0124','SN0125'),
'456-DEF': ('SN00333','SN00334','SN00335'),
'789-GHI': ('SN-0001','SN-0002','SN-0003','SN-0004')
}
And then reference using:
var vArrName = arr_PN->{vGivenPN};

using for loop and if statement to check id names with numbers

for (var i = 1; i < 81; i++){
if($(this).hasClass('member-'+i)){
('promote'+i) = true;
}
}
I have 80 droppable boxes. They each has an id called member-1, member-2, etc., when someone drags an item into the boxes, the variable will be turned to true and be passed to another function.
So far I found this is not working. I wasn't sure why. It is inside a droppable drop function.
since I have 80 boxes...I don't feel like typing them out manually.
Make promote an array, rather than 80 different variables. Then you can do:
var promote = [];
for (var i = 1; i < 81; i++){
if($(this).hasClass('member-'+i)){
promote[i] = true;
}
}
Much better would be to just see what classes do exist rather than testing for 81 different classes:
var matches, promotes = [], cls = this.className;
var regex = /member-(\d+)/g;
while (matches = regex.exec(cls)) {
// matches[1] contains the number from the member-xx class name
promotes.push(parseInt(matches[1], 10));
}
// promotes is an array that contain a list of the member-xx numbers that exist
// on this object

How to remove eval() from dynamic property calls and Uncaught ReferanceError

I'm trying to call object properties dynamically. I have solved the problem with eval() but i know that eval is evil and i want to do this on a better and safer way. My eval code:
// onfocus
var classes = this.getAttribute('class').split(' ');
for(var i = 0; i < classes.length; ++i) {
if(classes[i].match(/val\- */) !== null) {
var rule = classes[i].substr(4);
var instruction = eval('validate.instructionTexts.'+ rule +'()');
tooltip.appendChild( document.createTextNode(instruction) );
}
}
And I also have this code:
// onblur
var classes = this.getAttribute('class').split(' ');
for( var i = 0; i < classes.length; ++i ){
if(classes[i].match(/val\- */) !== null) {
var rule = classes[ i ].substr( 4 );
var tooltip = document.getElementsByClassName( 'tooltip' );
for( i = 0; i < tooltip.length; ++i){
tooltip[ i ].style.display = 'none';
}
eval('validate.rules.'+ rule +'(' + (this.value) + ')');
}
the problem with the second code is that I want to send a string to my property. this.value = the text i type in my textbox so i get correct string from this.value but i got this error.
if i type foo.
Uncaught ReferenceError: foo is not defined. Javascript thinks I trying to send a variabel but i want it to send a string. How can i solve this problems?
An HTML element's CSS class can be accessed directly from JS thru the className property.
JS object properties can be accessed via the dot-notation object.property or via the square-bracket-notation object['property'].
The regex /val\- */ matches the characters v, a, l, a '-' hyphen, and zero or more spaces, anywhere in the string.
The spaces are completely irrelevant since you're testing the result of a string that was split on spaces (and so it won't contain any spaces anymore).
Also, you're not anchoring the regex so a class of 'eval-test' will also be matched. I doubt that's what you're looking for.
If you were just testing for the classes starting with val-, then the indexOf method is much easier to read, and probably also a lot more efficient.
I've adjusted your bits of code accordingly. I'm assuming that the class names for your validation rules all start with val-, and that the rest of the class name is the name for the rule:
// onfocus
var classes = this.className.split(' ');
for(var i = 0; i < classes.length; ++i) {
if(classes[i].indexOf('val-') === 0) { // the class name starts with 'val-'
var rule = classes[i].substr(4);
var instruction = validate.instructionTexts[rule]();
tooltip.appendChild(document.createTextNode(instruction));
}
}
// onblur
var classes = this.className.split(' ');
for (var i = 0; i < classes.length; ++i ){
if(classes[i].indexOf('val-') === 0) { // the class name starts with 'val-'
var rule = classes[i].substr(4);
var tooltip = document.getElementsByClassName('tooltip');
for (i = 0; i < tooltip.length; ++i){
tooltip[i].style.display = 'none';
}
validate.rules[rule](this.value);
}
}
You do not need to use eval, you can access it as:
validate.rules[rule](this.value);
Which will solve your other problem too, which is that you are passing in the value of this.value which when eval()'d is not quoted as a string (which 'foo' is) so is being interpreted as a variable.
to get a property foo from object obj, you could use either
obj.foo
or
obj["foo"]
The first one won't allow reserved words or if the property contains spaces.
So your first example could change to
validate.instructionTexts[rule]()

find a href with a certain value

I have an array called "selectMe" formed by a variable wich contains a string such as: 12P, 5B, 10C, etc., this is the "href" value of a hyperlink and I need to find and add the class "selected" to the ones inside this array. To break the array I have:
function selectPrevious(selections){
// split into array
var selectMe = selections.split(", ")
for (var i = 0; i < selectMe.length; i++){
$('#theater a').search(selectMe[i]).addClass('selected');
}
}
I've tried doing find() instead of search() as well as many other iterations but still haven't been able to accomplish what I want, how can I do it?
EDIT
Using one of the answers provided here I have changed it to this:
function selectPrevious(selections){
// split into array
if(typeof selections !== "undefined"){
var selectMe = selections.split(", ");
for (var i = 0; i < selectMe.length; i++){
$('#theater a[href*='+selectMe[i]+']').addClass('selected');
}
}
}
I had to add the "if(typeof selections !== "undefined")" because otherwise it was throwing me errors on IE. Anyway, I still can't add the class "selected" to the values in the array, am I missing something? or did I do something wrong?
Your selector for find() is wrong. And there are no search() in jQuery.
Instead of $('#theater a').search(selectMe[i]) use $('#theater a[href*='+selectMe[i]+']')
try this one:
function selectPrevious(selections) {
// split into array
var selectMe = selections.split(", ")
for (var i = 0; i < selectMe.length; i++){
$('#theater').find('a[href*='+selectMe[i]+']').addClass('selected');
}
}

Categories

Resources