Getting a value from #Html.DisplayFor and #Html.HiddenFor - javascript

The HTML
int i = 1;
foreach (var item in Model.MyDataset)
{
<td class="tdBorder">
#Html.DisplayFor(x => item.ID, new { id = "VisibleID" + #i })
#Html.HiddenFor(x => item.ID, new { id = "HiddenID" + #i })
</td>
i += 1;
}
The jQuery
for (i = 1; i <= rowCount; i++) {
var myID_Visible = $.trim($("#VisibleID" + i).val());
var myID_Hidden = $.trim($("#HiddenID" + i).val());
}
I'm trying to learn some MVC and jQuery.
Would some one explain to me why calling
var myID_Visible = $.trim($("#VisibleID" + i).val()); returns an empty string but
var myID_Hidden = $.trim($("#HiddenID" + i).val()); returns the value of my item.ID?
The only difference is that the first jQuery line refers to a #Html.DisplayFor (returns empty string) while the second jQuery line refers to a #Html.HiddenFor (returns actual value).
Why can't i get a value from the #Html.DisplayFor?

Because #Html.DisplayFor() does not render a control and you cannot use .val(). Instead use
myID_Visible = $.trim($("#VisibleID" + i).text())
although this will depend on the html that #Html.DisplayFor() is rendering (are you using a display template?). You need to check the html generated.
By default DisplayFor will just render the text value of the property. You would need to do something like
int i = 1;
#foreach (var item in Model.MyDataset)
{
<td class="tdBorder">
<span id="#i">
#Html.DisplayFor(x => item.ID)
</span>
#Html.HiddenFor(x => item.ID, new { id = "HiddenID" + #i })
</td>
i += 1;
}
and in the script
myID_Visible = $.trim($('#' + i).text());

Some input has .html() rather than .val() try:
var myID_Visible = $.trim($("#VisibleID" + i).html());
EDIT
Another thing, remove the # before the i, you are already inside a C# code
#Html.DisplayFor(x => item.ID, new { id = "VisibleID" + i })

The reason is explained in this and that.
For your case however, I prefer to make it like this:
HTML
int i = 1;
foreach (var item in Model.MyDataset)
{
<td class="tdBorder">
<p id="VisibleID#(i)">#Html.DisplayFor(x => item.ID)</p>
<p id="HiddenID#(i)">#Html.HiddenFor(x => item.ID)</p>
</td>
i += 1;
}
So in the script we can call it:
for (i = 1; i <= rowCount; i++) {
var myID_Visible = $("#VisibleID" + i).text();
var myID_Hidden = $("#HiddenID" + i).text();
}
Hopefully this can help you, cheers!

#Html.DisplayFor(x => item.ID, new { id = "VisibleID" + #i })
rendred html looks like:
<span id="VisibleID1">item id value here</span>
whereas
#Html.HiddenFor(x => item.ID, new { id = "HiddenID" + #i })
rendered html looks like
<input type="hidden" id="HiddenID1" value="item id value here">
So in order to have display for value you should you use, $("#VisibleID1).html() as noted by #Shadi

Related

Dynamic Query Selector with own Event Listener

Hi i am using Javascript to Call a API for Pricefeed from Coingecko. I use a Function to add Div's from a button for choosing Coins that will display Prices in different "spaces".
HTML:
<button onclick="add_coin('coinspaceA', window.countA); return false;">Add Coin</button>
<button onclick="add_coin('coinspaceB', window.countB); return false;">Add Coin</button>
<button onclick="add_coin('coinspaceC', window.countV); return false;">Add Coin</button>
i call the Function fetch_coinlist() before the closing Body Tag
JS:
window.countA = 0;
window.countB = 0;
window.countC = 0;
var coins = {};
function fetch_coinlist(){
fetch("https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false")
.then(
function(response) {
if (response.status !== 200) {
alert('Can Not get Price Api! Status: ' +
response.status);
return;
}
// Examine the text in the response
response.json().then(function(data) {
coins = {};
for (let i = 0, l = data.length; i < l; i++) {
let {id, ...info} = data[i];
coins[id] = info;
}
});
}
)
.catch(function(err) {
alert('Can Not get Price Api! Status: ' + err);
});
}
function add_coin(space) {
if (space == "coinspaceA") {
coinspace(space, window.countA);
}
if (space == "coinspaceB") {
coinspace(space, window.countB);
}
if (space == "coinspaceC") {
coinspace(space, window.countC);
}
}
function coinspace(space, count){
const div = document.createElement('div');
count += 1;
div.id = space + count;
if (space == "coinspaceA"){
window.coinspace1 = count;
}
if (space == "coinspaceB"){
window.coinspace2 = count;
}
if (space == "coinspaceC"){
window.coinspace3 = count;
}
div.innerHTML = (`
<input type="button" value="-" class="curser-del" onclick="remove_coin(this,'` + space + `')"/>
<select id="` + space + count + `select" placeholder="Choose Coin"></select>
<input type="numbers" >
<label id="` + space + count + `info">Coins</label>
`);
document.getElementById(space).appendChild(div);
show_coinlist(space, count);
}
function show_coinlist(space, count){
for (let id in coins) {
let item = coins[id];
console.log(item);
const toplist = document.createElement("option");
toplist.value = id;
console.log(toplist.value);
// selector actions
const selector = document.querySelector("#" + space + count + "select");
const info = document.querySelector("#" + space + count + "info");
console.log(selector);
console.log(info);
selector.addEventListener('change', event => {
info.innerHTML = "Selected item: " + coins[toplist.value].name + " : " + coins[toplist.value].current_price;
});
console.log(coins[toplist.value].name);
console.log(coins[toplist.value].current_price);
toplist.innerHTML = item.symbol.toUpperCase() + " - " + item.name;
console.log(toplist.innerHTML);
console.log(toplist);
document.getElementById("#" + space + count + "select").appendChild(toplist);
}
}
When i use the selector on its own with a static ID it works and i get the Price Displayed from the Coin i choose, in the example above it gives me the right Values to the Console but when i try to run the loop it gets aborted after the first cycle with the error:
Uncaught TypeError: Cannot read property 'appendChild' of null
I tryed to put the script at the End of the Site so everything can load, but it does not change the Error, i tryed with static ID this works but i need to have as many selections as the User wants to add, i tryed to put selector Actions outside the loop but it did not work either. When i use console.log(toplist) before ...appendChild(toplist) it gives me the correct option i try to append,
<option value="bitcoin">BTC - Bitcoin</option>
but the loop stops with the Error: Uncaught TypeError: Cannot read property 'appendChild' of null, what am i doing wrong?

jquery select custom attribute in child controls

I have a table with class="cloneable" that has rows containing one control per row. The controls may be textarea, checkbox, radio, or input[type=number]. Each control has a custom data-answersetid attribute. I would like to select all child controls under the .cloneable class and update each of the data-answersetid attributes to the value of a counter variable, lastanswersetid. I tried the following but it didn't work.
let lastanswersetid: number = 0;
const me: any = $('.cloneable').last(); //there might be several cloneables so just get the last cloneable
$('*[answersetid]', me) ? .each(function(index, value) {
console.log(index, value);
console.log($(this));
lastanswersetid++;
$(this).prop('aswersetid', lastAnswersetid);
}); //set the data-answersetid to the last answerset value
<table id="questionTable" class="table #("Q33,Q65".Contains(Model.QuestionnaireAndChoices.First().QuestionKey) ? "cloneable" : "")">
<tbody>
#foreach (var item in Model.QuestionnaireAndChoices)
{
<tr id="#item.QuestionID"
#("Q64".Contains(item.QuestionKey) ? "class=cloneable" : "Q70,Q71".Contains(item.QuestionKey) ? "class=notCloneable" : "")>
<td>
#Html.DisplayFor(modelItem => item.QuestionKey)
</td>
<td class="question">
#Html.DisplayFor(modelItem => item.Question)
</td>
<td>
#switch (item.ChoiceUIType)
{
case "UI-CHK":
#await Component.InvokeAsync("Checkbox2", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices });
break;
case "UI-DROP1":
#await Component.InvokeAsync("Dropdown2", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices });
break;
case "UI-RAD":
#await Component.InvokeAsync("RadioButton2", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices, question = item.Question, radioGroupName = item.QuestionKey });
break;
case "UI-NUMBER":
{
int thisLength = 10;
string thisUiWidth = "150px";
if (item.QuestionKey == "Q38")
{
thisLength = 3;
}
#await Component.InvokeAsync("Input", new { userID = Model.UserID, questionID = item.QuestionID, questionKey = item.QuestionKey, choiceList = item.Choices, inputLength = thisLength, uiWidth = thisUiWidth });
break;
}
case "UI-TXT":
{
<div class="md-form amber-textarea active-amber-textarea">
<textarea name="#item.QuestionKey" id="#item.QuestionKey" class="md-textarea form-control persistable" rows="3"
data-questionid="#item.QuestionID" data-userid="#Model.UserID"
data-questionkey="#item.QuestionKey"
data-useranswerid="#item.Choices.FirstOrDefault()?.UserAnswerID"
data-codesetid="#item.Choices.FirstOrDefault()?.ChoiceID"
data-oldvalue="#item.Choices.FirstOrDefault()?.OtherDescription"
data-answersetid="#item.Choices.FirstOrDefault()?.AnswerSetID"
data-toggle="tooltip" data-placement="left"
title="#(!string.IsNullOrEmpty(item.Choices.FirstOrDefault()?.OtherDescription) ? string.Format("Answered by {0}", item.Choices.First().AnsweredBy) : "")">#item.Choices.FirstOrDefault()?.OtherDescription</textarea>
</div>
break;
}
default:
{
#*just display the text*#
<div>Render raw text here</div>
break;
}
}
</td>
</tr>
}
</tbody>
</table>
Your selector is wrong, it should be [data-answersetid], also use .data() to set the value.
$('[data-answersetid]', me) ? .each(function(index, value) {
console.log(index, value);
console.log($(this));
lastanswersetid++;
$(this).data('answersetid', lastAnswersetid);
}); //set the data-answersetid to the last answerset value
If you need the actual attribute in the DOm updated you'd need to use .attr()
$(this).attr('data-answersetid', lastAnswersetid);

Reducing code with the use of Handlebars.js

I'm beginning to use Handlebars and the architectural pattern Model View ViewModel and I wrote this code :
var data = {
currentPlayer: this._model.currentPlayer,
line: [
{
row:
[
{
caseNumber:1,
caseValue: this._model.getCaseState(0,0)
},
{
caseNumber:2,
caseValue: this._model.getCaseState(0,1)
},
{
caseNumber:3,
caseValue: this._model.getCaseState(0,2)
}
]
},
{
row:[
{
caseNumber:4,
caseValue:this._model.getCaseState(1,0)
},
{
caseNumber:5,
caseValue:this._model.getCaseState(1,1)
},
{
caseNumber:6,
caseValue:this._model.getCaseState(1,2)
}
]
},
{
row:[
{
caseNumber:7,
caseValue:this._model.getCaseState(2,0)
},
{
caseNumber:8,
caseValue:this._model.getCaseState(2,1)
},
{
caseNumber:9,
caseValue: this._model.getCaseState(2,2)
}
]
}
]
};
var htmlContent = this._template(data);
this._element.html(htmlContent);
With the following template :
<div>
<h3>It is to player {{currentPlayer}}</h3>
<table>
{{#each line}}
<tr>
{{#row}}
<td data="{{caseNumber}}" class="case{{caseValue}}">{{caseValue}}</td>
{{/row}}
</tr>
{{/each}}
</table>
</div>
This code works fine but I'm asking if I cannot reduce it. So I tried to use a for loop in the var data but I realized that I can't do this.
My other choice was to use an if in the template like this :
{{#each line}}
<tr>
{{#row}}
{{#if caseValue}}
<td data="{{caseNumber}}" class="case{{caseValue}}">O</td>
{{else}}
<td data="{{caseNumber}}" class="case{{caseValue}}">X</td>
{{/if}}
{{/row}}
</tr>
{{/each}}
by testing the value of the var caseValue. However, as caseValue takes the value of 1 or 0 or undefined, if the case isn't checked all the cells are filled with a "X".
So, I can't find a compact solution with the aim of :
At the beginning, all the TD tags are empty.
Depending on the value of getCaseState which returns 0 or 1 fill
the cell with an "X" or an "O".
EDIT : I manage the different values of getCaseState with this code :
Handlebars.registerHelper('displayTd', function(data) {
var result;
if(data.caseValue === undefined) {
result = '<td data="' + data.caseNumber + '"></td>';
return new Handlebars.SafeString(result);
} else if(data.caseValue === 1) {
result = '<td data="' + data.caseNumber + '" class="case' + data.caseValue + '">X</td>';
return new Handlebars.SafeString(result);
} else {
result = '<td data="' + data.caseNumber + '" class="case' + data.caseValue + '">O</td>';
return new Handlebars.SafeString(result);
}
});
The first step I would take to reduce the code was the one you alluded to about using loops to construct your data. The data in your line object follows a simple pattern, so we can construct with the following code:
var numRows = 3;
var numColumns = 3;
var line = [];
for (var rowIndex = 0; rowIndex < numRows; rowIndex++) {
line[rowIndex] = { row: [] };
for (var columnIndex = 0; columnIndex < numColumns; columnIndex++) {
line[rowIndex].row[columnIndex] = {
caseNumber: ((rowIndex * numColumns) + columnIndex + 1),
caseValue: getCaseState(rowIndex, columnIndex)
};
}
}
*Note that you will have to call getCaseState on your existing model object.
Our data object then becomes:
var data = {
currentPlayer: this._model.currentPlayer,
line: line
};
As for the conditional within your template, I would recommend creating your own Handlebars helper. Fortunately, Handlebars has an isEmpty utility method that returns true for:
Array with length 0
falsy values other than 0
This means that we can use this utility method to check if our caseValue is undefined:
Handlebars.registerHelper('getCharacter', function (caseValue) {
return Handlebars.Utils.isEmpty(caseValue) ? '' : (caseValue === 0 ? 'X' : 'O');
});
We then use our new helper in our template in the following way:
{{#each row}}
<td data="{{caseNumber}}" class="case{{caseValue}}">{{getCharacter caseValue}}</td>
{{/each}}

Javascript: could not get the value inside an array using for in loop

I want to display the form with user filled values inside the form to admin. I have displayed all type of values to the respective type of input/select/textarea tags (type: text,email, tel,number... etc) except input type=checkbox.
I am getting problem while fetching the values from array that contain values of group of checkboxes. My code is
var value = data[i][key];
var result = $.isArray(value);
if (result == true) {
var string = key;
var splitstring = string.split("#");
for (var value1 in value) {
console.log(value1);
$("input[type='checkbox'][groupid='" + splitstring[0] + "'][value='" + value1 + "']").attr('checked', true); //cb
}
}
my array(named value) contain values like
[cricket, football, tennis]
would like to make the checkbox property checked that match the condition. but when i console the values fetched one by one it shows me output as
0
1
2
i am not getting what is it???
my html code
<table class="form-group">
<tbody id="tedit">
<tr>
<td>
<div class="checkbox">
<input id="dddddddd#1428735544884535#check_box1" class="form-control" name="14287355448849394#dddddddd[]" groupid="14287355448849394" grid-name="dddddddd" value="Check Box1" type="checkbox" /><label class="jedit"><span class="mouseover">Check Box1</span></label>
</div>
</td>
</tr>
<tr>
<td>
<div class="checkbox">
<input id="dddddddd#14287355448843282#check_box2" class="form-control" groupid="14287355448849394" grid-name="dddddddd" name="14287355448849394#dddddddd[]" value="Check Box2" type="checkbox" /> <label class="jedit"> <span class="mouseover">Check Box2</span></label>
</div>
</td>
</tr>
<tr>
<td>
<div class="checkbox">
<input id="dddddddd#14287355448853367#check_box3" class="form-control" groupid="14287355448849394" grid-name="dddddddd" name="14287355448849394#dddddddd[]" value="Check Box3" type="checkbox" /> <label class="jedit"> <span class="mouseover">Check Box3</span></label>
</div>
</td>
</tr>
</tbody>
</table>
my javascript code is
$.post('<?php echo BASE_URL . 'php/processing/formDashboard/formEntryShowOneByOne.php' ?>', {id: $('#formMetaDataId').val()}, function(data) {
console.log(data);
for (var i = 0, len = data.length; i < len; i++) {
for (var key in data[i]) {
$("input[type='text'][name='" + key + "']").val(data[i][key]); //input tags
$("input[type='text'][name='" + key + "']").prop('disabled', 'true'); //input tags
//........likewise for other type of elements.......///
//.....................for checkbox........................//
var value = data[i][key];
var result = $.isArray(value);
if (result == true) {
var string = key;
var splitstring = string.split("#");
for (var value1 in value) {
console.log(value1);
$("input[type='checkbox'][groupid='" + splitstring[0] + "'][value='" + value1 + "']").attr('checked', true); //cb
}
}
}
}
});
this is simple. The 'cricket' string is retrievable like this:
value[value1]
value1 is just the iterator, in your example 0,1,2
This is your working code:
var value = data[i][key];
var result = $.isArray(value);
if (result == true) {
var string = key;
var splitstring = string.split("#");
for (var value1 in value) {
console.log(value[value1]);
$("input[type='checkbox'][groupid='" + splitstring[0] + "'][value='" + value[value1] + "']").attr('checked', true); //cb
}
}
You should use forEach function
value.forEach(function(val)
{
console.log(val);
//do your thing here
});
That's just how the for ... in loop works for arrays:
var a = ['a','b','c'];
for (var i in a) {
alert(i); // alerts 0,1,2
alert(a[i]); // alerts a,b,c
}
Thus, you just need to index your array with the loop variable:
var value = data[i][key];
var result = $.isArray(value);
if (result == true) {
var string = key;
var splitstring = string.split("#");
for (var valueIndex in value) {
console.log(value[valueIndex]);
$("input[type='checkbox'][groupid='" + splitstring[0] + "'][value='" + value[valueIndex] + "']").attr('checked', true); //cb
}
}

Input number's value to append div's

Fiddle - http://liveweave.com/enRy3c
Here's what I'm trying to do.
Say my input number is 5. I want to dynamically append 5 divs to the class .enfants. However I haven't figured out how to do that. I been searching and searching and I haven't came across anything.
jQuery/JavaScript:
var counter = 1;
// Value number = .enfants children
$(".ajouter-enfants").on('keyup change', function() {
var yourChildren = "<div>" + counter++ + "</div>";
var CallAppend = function() {
$(".enfants").append( yourChildren );
};
// If 0 or empty clear container
if ( $.inArray($(this).val(), ["0", "", " "]) > -1 ) {
$(".enfants").html("");
// If only add/have 1 div in container
} else if ($(this).val() === "1") {
$(".enfants").html("").append( yourChildren );
// If > 0 add as many divs as value says
} else {
$(".enfants").html("");
CallAppend();
}
});
HTML:
<div class="contenu" align="center">
<div>
Value number = .enfants children
</div>
<input type="number" min="0" class="ajouter-enfants" value="0" />
<div class="enfants">
</div>
</div>
How about a simple loop? If you just want to append, try something like this:
$(".ajouter-enfants").on('change', function() {
var numDivs = $(this).val();
var i;
for (i = 1; i <= numDivs; i += 1) {
$('.enfants').append('<div>' + i + '</div>');
}
});
EDIT:
If you want to replace instead of append the newly-created <div>'s, try something like:
$(".ajouter-enfants").on('keyup change', function() {
var content = '';
var numDivs = $(this).val();
var i;
for (i = 1; i <= numDivs; i += 1) {
content += '<div>' + i + '</div>';
}
$('.enfants').html(content);
});
This will replace the entire content of any elements using the class ajouter-enfants with the number of <div>'s specified in the input box.
Try this:
$(".ajouter-enfants").on('keyup change', function() {
var num = +$.trim($(this).val()), target = $(".enfants"), i = 0, s = '';
target.empty();
if (!isNaN(num) && num > 0) {
for (; i < num; i++) {
s += '<div>' + (i + 1) + '</div>';
}
target.html(s);
}
});
How would you get it to only append the value amount? It appends more when the value is (2 becomes 3, 3 becomes 6, 4 becomes 10 and repeats even when I'm decreasing the numeric value) –
#Michael Schwartz
Here is another code example that might be helpfull.
$(".ajouter-enfants").on('change', function() {
var numDivs = $(this).val();
var i;
var html ='';
for (i = 1; i <= numDivs; i += 1) {
html += '<div>' + i + '</div>';
}
$('.enfants').empty().append(html);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="contenu" align="center">
<div>
Value number = .enfants children
</div>
<input type="number" min="0" class="ajouter-enfants" value="0" />
<div class="enfants">
</div>
</div>

Categories

Resources