I Have the following code within my razor view that I want to action a button next to every response.
Once clicked I want it to copy response to actualresponse.
But I get the following error
Microsoft JScript runtime error: Unable to get value of the property 'foo': object is null or undefined.
#for (int i = 0; i < Model.Responses.Count(); i++)
{
<div class="col-md-4">
#Html.LabelFor(x => Model.Responses[i].Response, htmlAttributes: new { #class = "control-label"})
#Html.DisplayFor(x => Model.Responses[i].Response)
</div>
<input type="button" name="set_Value" id="#i" value="Copy Response to Actual Response" class="btn btn-success" dataset-foo="#Model.Responses[i].Response" onclick="setVale(this)" />
<div class="col-md-4">
#Html.LabelFor(x => Model.Responses[i].ActualResponse, htmlAttributes: new { #class = "control-label"})
#Html.TextAreaFor(x => Model.Responses[i].ActualResponse, htmlAttributes: new { #class = "from-control", #id = "actualResponse-" + i, rows = 5, columns = 40})
</div>
<script type="text/javascript">
function setValue(btn)
{
var id = btn.id;
var value = btn.value;
var foo = btn.dataset.foo;
document.getElementById('actualResponse-' + id).value = foo
}
</script>
}
Your for loop creates multiple copies of a function with the same name. The last function with the hardcoded id is the result you see.
You could just pass this into your click handler.
<input type="button" name="set_Value"
value="Copy Response to Actual Response" class="btn btn-success"
id = "#i"
data-foo = "#foo"
onclick="setVale(this)" />
Then you can stop that ugly mixing of Razor and JavaScript. And take the function out of the for loop so you only have one setValue() which will handle all instances of your buttons.
function setValue(btn) {
var id = btn.id;
var value = btn.value;
var foo = btn.dataset.foo;
}
Related
I'm having a problem getting the form values by passing the two query parameters, id and type, from the url.
Let's assume the URL is:
... page.html?id=14&type=Title
I want the values of these to be shown in the form to then make the change later.
function getQueryVariable () {
var query = window.location.search.substring (1);
var vars = query.split ("&");
for (var i = 0; i <vars.length; i ++) {
var pair = vars [i] .split ("=");
}
}
function onLoad () {
var value = getQueryVariable ();
var id = document.getElementById ('id');
var type = document.getElementById ('type');
id.value = value;
type.value = value;
}
<div class = "container">
<form method ="post" id="save" action="javascript: myFunction()" onload="onLoad()">
<div class = "field">
<label for = "id"> ID: </label>
<input type = "number" id = "id" name = "id" />
</div>
<div class = "field">
<label for = "type"> Fragment Type: </label>
<input type = "text" id = "type" name = "type" />
</div>
<div class = "field">
<button type = "submit" class = "full"> Save changes </button>
</div>
</form>
</div>
As you can see from the code, I call the onLoad() function to load the data into the form.
I don't get any errors; the values of the getQueryVariable() function variables are correct, but I notice that it is not called.
myFunction() is not shown, but this is the function that will serve me later to modify the fields of the form.
Could you kindly help me?
First of all, you need to execute onLoad function,
then you need to create an object to store the values and pass it to another function.
And your loop is really out of the world, I corrected it, please try to understand my code and if you have questions feel free to comment.
Here you go, for query, I changed it to a string that you provided as an exemple, so it would work in snippet.
function getQueryVariable () {
var object = {}
var query = "id=14&type=Hello%20Title";
var vars = query.split ("&");
for (var i = 0; i <vars.length; i ++) {
let splitted = vars[i].split('=')
object[splitted[0]] = decodeURI(splitted[1])
}
return object;
}
function onLoad () {
var pairs = getQueryVariable ();
var id = document.getElementById ('id');
var type = document.getElementById ('type');
id.value = pairs.id;
type.value = pairs.type;
}
onLoad();
<div class = "container">
<form method ="post" id="save" action="javascript: myFunction()" onload="onLoad()">
<div class = "field">
<label for = "id"> ID: </label>
<input type = "number" id = "id" name = "id" />
</div>
<div class = "field">
<label for = "type"> Fragment Type: </label>
<input type = "text" id = "type" name = "type" />
</div>
<div class = "field">
<button type = "submit" class = "full"> Save changes </button>
</div>
</form>
</div>
Your getQueryVariable () function is not returning anything. You can try something like this:
function getQueryVariable () {
var query = window.location.search.substring (1);
var vars = query.split ("&");
var params = {}
for (var i = 0; i <vars.length; i ++) {
var pair = vars [i] .split ("=");
params[pair[0]] = pair[1]
}
return params
}
function onLoad () {
var params = getQueryVariable ();
var id = document.getElementById ('id');
var type = document.getElementById ('type');
id.value = params.id ;
type.value = params.type ;
}
I have a web page with two TextBoxFor fields that utilize Javascript autocomplete. With one of the fields, ClientUser, the response includes an integer and a string. The integer is then compared with another integer field on the page, ClientID, and if they match, the string is used in the autocomplete suggestions. The other field's response, WorkmateUser, is a string list immediately usable in the autocomplete.
The controller is being hit and returning the correct total list, then the correct Url/field needing validation is chosen, but the list needing validation is undefined for the ClientUser autocomplete field needing validation. What is the most efficient way to compare an integer field on the page with an integer returned for the autocomplete list? Thanks in advance!
Razor:
<div class="row">
<div class="col-lg-12">
#Html.LabelFor(m => m.WorkmateUser, "Workmate To Add", new { #class = "control-label" })
#Html.TextBoxFor(m => m.WorkmateUser, new { data_autocomplete_url = Url.Action("GetWorkmates"), #class = "form-control" })
</div>
</div>
<div class="row">
<div class="col-lg-8">
#Html.LabelFor(m => m.ClientID, "Firm To Include", "--Choose Firm--")
#Html.DropDownListFor(m => m.ClientID, StaticCache.GetClients(Model.UserID), new { #class = "form-control" })
</div>
</div>
<div class="row">
<div class="col-lg-8">
#Html.LabelFor(m => m.ClientUser, "Client To Add", new { #class = "control-label" })
#Html.TextBoxFor(m => m.ClientUser, new { data_autocomplete_url = Url.Action("GetAllClients"), #class = "form-control" })
</div>
</div>
Javascript:
<script type="text/javascript" language="javascript">
$(document).ready(function () {
$('*[data-autocomplete-url]')
.each(function () {
var $url = $(this);
$(this).autocomplete({
source: $(this).data("autocomplete-url"),
response: function (data) {
if ($(this).data("autocomplete-url") == "/Message/GetAllClients") {
var aList = [];
for (var i = 0; i < data.length; i++) {//data.length is undefined!!!
if (data[i].ClientID == $("#ClientID").val()) {
aList.push(data[i].FirstName);
}
}
return bros;
}
else {
return data;
}
}
});
});
});
</script>
It's probably not the most elegant solution, but I ended up separating out the autocomplete call that needs validation into its own script and passing the additional variable into the controller to do validation on the back end. The following works:
Script:
<script>
$(document).on('keyup', '#ClientUser', function () {
var abID = $(this),
cID = $("#ClientID").val(),
cList = [];
$.ajax({
type: "GET",
url: '#Url.Action("GetAllClients", "Message")',
data: { term: abID.val(), clientID: cID },
success: function (data) {
for (var i = 0; i < data.length; i++) {
cList.push(data[i]);
}
},
error: function () {
alert("Client employeess could not be pulled.");
}
});
abID.autocomplete({
source: cList
});
});
</script>
I want to change Editorfor that display already data from database when i change input
i will take output of input and split it and put result in 2 EditorFor
<input type="text" value="Set Date" id="reservationtim onchange=myFunction()>
#Html.EditorFor(model => model.StartDate, new { htmlAttributes = new { #class = "form-control" }, id = "startDate" })
#Html.EditorFor(model => model.EndDate, new { htmlAttributes = new { #class = "form-control" } , id = "endDate" })
and the function :
<script>
function myFunction() {
var date = document.getElementById("reservationtime").value;
var res = date.split("-");
model => model.StartDate = res[0];
document.getElementById("startDate") = res[0];
document.getElementById("endDate") = res[1];
}
</script>
You're trying to set the element reference itself to the value you want. Rather you need to set the value attribute of the element reference:
document.getElementById("startDate").value = res[0];
Also, it looks like you're trying to mix server-side and client-side code here. Remember that JavaScript is not processed until the document has already been processed by the server and returned to the client. Once you're client-side, all that exists is just the DOM, which is created by the browser based on the HTML document the server sent down. In other words, the fact that you used EditorFor or whatever is completely lost. All you have is the result (i.e. HTML) of that call to EditorFor.
You should first correct your HTML, as some attributes are not specified correctly.
<input type="text" value="Set Date" id="reservationtime" onchange="myFunction()">
#Html.EditorFor(model => model.StartDate, new { #class = "form-control" } )
#Html.EditorFor(model => model.EndDate, new { #class = "form-control" } )
I don't know why you are explicitly setting id for above two editors. they by default take property name as ID. so I would suggest following script for it.
<script>
function myFunction() {
var date = document.getElementById("reservationtime").value;
var res = date.split("-");
model => model.StartDate = res[0];
if(res.length>1) {
document.getElementById("StartDate").value = res[0];
document.getElementById("EndDate").value = res[1];
// if you still want to set ID properties instead of using default use following
// document.getElementById("StartDate").value = res[0];
// document.getElementById("EndDate").value = res[1];
}
}
</script>
I kind of messed up the logic of my code, and I can't figure out how to fix it. I have a Bootstrap navtab panel that when the tabs are clicked, based on which tab is clicked it runs an MVC C# function in my controller. I actually need this to happen on a button click. SO the user enters a date into the datepicker, clicks submit, and then based on which tab is selected, a function will be run. How can I do this on a button click?
Here is my datepicker and button:
<div class="row spiff-datepicksection">
<div class="col-lg-6 pull-right">
<div class="col-sm-5 col-lg-offset-4">
<div class="form-group">
<div class="input-group date">
<input id="startDate" type="text" class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
<div class="col-lg-3">
<input class="spiffdate-btn" type="submit" value="Submit" />
</div>
</div>
</div>
Here is my javascript:
<script>
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var wrongid = $('.tab-content .active').attr('id');
$('a[data-toggle="tab"]').removeClass("active");
$(this).addClass("active");
var correctid = $(this).data("id");
alert($('.tab-content .active')[0].outerHTML);
var startDate = $('#startDate').val();
if (correctid == "delayedspiff")
$.get("#Url.Action("DelayedSpiffDate", "Dashboard")", { startDate: startDate });
else
$.get("#Url.Action("InstantSpiffDate", "Dashboard")", { startDate: startDate });
});
</script>
And here is my controller if it is needed:
public ActionResult DelayedSpiffDate(DateTime startDate)
{
var available = _appService.GetFeatureStatus(1, "spiffDashboard");
if (!available)
return RedirectToAction("DatabaseDown", "Error", new { area = "" });
var acctId = User.AccountID;
//startDate = DateTime.Today.AddDays(-6); // -6
var endDate = DateTime.Today.AddDays(1); // 1
Dictionary<DateTime, List<SpiffSummaryModel>> dict = new Dictionary<DateTime, List<SpiffSummaryModel>>();
try
{
var properties = new Dictionary<string, string>
{
{ "Type", "DelayedSpiff" }
};
telemetry.TrackEvent("Dashboard", properties);
dict = _reportingService.GetDailyDelayedSpiffSummaries(acctId, startDate, endDate);
}
catch (Exception e)
{
if (e.InnerException is SqlException && e.InnerException.Message.StartsWith("Timeout expired"))
{
throw new TimeoutException("Database connection timeout");
}
var error = _errorCodeMethods.GetErrorModelByTcError(PROJID.ToString("000") + PROCID.ToString("00") + "001", "Exception Getting DelayedSpiff Dashboard View", PROJID, PROCID);
error.ErrorTrace = e.ToString();
_errorLogMethods.LogError(error);
return RedirectToAction("index", "error", new { error = error.MaskMessage });
}
var spiffDateModels = new List<DelayedSpiffDateModel>();
foreach (var entry in dict)
{
var spiffDateModel = new DelayedSpiffDateModel();
spiffDateModel.Date = entry.Key;
spiffDateModel.Carriers = new List<DelayedSpiffCarrierModel>();
foreach (var item in entry.Value)
{
var spiffCarrierModel = new DelayedSpiffCarrierModel();
spiffCarrierModel.Carrier = item.CarrierName;
spiffCarrierModel.CarrierId = item.CarrierId;
spiffCarrierModel.ApprovedSpiffTotal = item.ApprovedSpiffTotal;
spiffCarrierModel.EligibleActivationCount = item.EligibleActivationCount;
spiffCarrierModel.IneligibleActivationCount = item.IneligibleActivationCount;
spiffCarrierModel.PotentialSpiffTotal = item.PotentialSpiffTotal;
spiffCarrierModel.SubmittedActivationCount = item.SubmittedActivationCount;
spiffCarrierModel.UnpaidSpiffTotal = item.UnpaidSpiffTotal;
spiffDateModel.Carriers.Add(spiffCarrierModel);
}
spiffDateModels.Add(spiffDateModel);
}
spiffDateModels = spiffDateModels.OrderByDescending(x => x.Date).ToList();
return PartialView(spiffDateModels);
}
Any ideas on how to make this happen on a button click?
You can try to create a handler of the 'click' event, which should retrieve a valid identifier of the selected tab and send a GET request to the server.
$(".spiffdate-btn").click(function(){
var correctid = $(".tab-content .active").attr("id");
var startDate = $("#startDate").val();
if (correctid == "delayedspiff")
$.get("#Url.Action("DelayedSpiffDate", "Dashboard")", { startDate: startDate });
else
$.get("#Url.Action("InstantSpiffDate", "Dashboard")", { startDate: startDate });
});
I realize this is an old question, but I am struggling with a similar issue so I am looking at old questions.
I think I see your problem though:
<script>
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
Your script calls "on shown".
If you do not want it running when it is shown, change it to "on click".
How? I can't help you with that yet. My javascript isn't that good.
In my index.cshtml file I have a razor element (#Html.EditorFor) that's a text box. Javascript isn't recognizing the element. If I change the element type to a non-razor syntax then javascript can see it. Am I missing some syntax here.
index.cshtml
<div class="jumbotron">
<h1>my application</h1>
#using (Html.BeginForm("Results", "Home", FormMethod.Post))
{
<div class="form-group">
//javascript can't see mainpagequery
#Html.EditorFor(model => model.SearchQuery, new { htmlAttributes = new { #class = "form-control", id = "mainpagequery" }})
#Html.ValidationMessageFor(model => model.SearchQuery, "", new { #class = "text-danger" })
//javascript can see mainpagequery in the non razor element here
<input type="text" class="form-control" placeholder="Search" id="mainpagequery">
</div>
<button type="submit" class="btn btn-default">Search</button>
}
Here is my javascript. If I use razor then 'mainpagequery' is underlines because it can't see it, if I use html then it's fine. I know I'm hitting my javascript because I see the alert message pop up.
$(document).ready(function () {
console.log("ready!");
alert("mainpage autocomplete function entered");
var input = document.getElementById('mainpagequery');
var options = {
types: ['(cities)'],
componentRestrictions: { country: "us" }
};
var mainpagequery = new window.google.maps.places.Autocomplete(input, options);
});
In case of #Html.EditorFor your id get overriden to model's property name.
If you find element using f12 you will find it as follows. (Notice id "SearchQuery124" I just renamed it to something)
So in your case in make change like
$(document).ready(function () {
console.log("ready!");
alert("mainpage autocomplete function entered");
var input = document.getElementById('SearchQuery').value;
console.log(input);
var options = {
types: ['(cities)'],
componentRestrictions: { country: "us" }
};
var mainpagequery = new window.google.maps.places.Autocomplete(input, options);
});
Try this
Instead of #Html.EditorFor use
#Html.TextBoxFor(model => model.SearchQuery, new { #class = "form-control" , id = "mainpagequery"})