I am developing asp.net mvc application. I have a section on the form where I add some text boxes dynamically when the user clicks a "Add New Part" button. The problem is when I submit the form I don't get the data from the fields I added dynamically. I am passing the FormCollection to my controller and stepping through the code in the debugger and those fields are not there. If I look at them in firebug I see them just fine. Any ideas?
Here is the javascript for adding the text fields to the page:
function moreFields() {
var newFields = document.getElementById('readrootpu').cloneNode(true);
newFields.id = '';
newFields.style.display = 'block';
var newField = newFields.childNodes;
for (var i = 0; i < newField.length; i++) {
var theName = newField[i].name
if (theName)
newField[i].name = theName;
}
var insertHere = document.getElementById('newpartusageitems');
insertHere.parentNode.insertBefore(newFields, insertHere);
}
Here is the html:
<div id="readrootpu" class="usedparts" style="display: none">
<% var fieldPrefix = "PartUsage[]."; %>
Part ID:
<%= Html.TextBox(fieldPrefix + "ID", "")%>
Serial Number:
<%= Html.TextBox(fieldPrefix + "Serial", "")%>
Quantity:
<%= Html.TextBox(fieldPrefix + "Quantity", "") %>
<input type="button" value="Remove" onclick="this.parentNode.parentNode.removeChild(this.parentNode);" />
</div>
When I inspect the html with firebug it looks fine to me:
Part ID: <input type="text" name="PartUsage[].ID" id="PartUsage[]_ID" value="" />
Serial Number: <input type="text" name="PartUsage[].Serial" id="PartUsage[]_Serial" value="" />
Quantity: <input type="text" name="PartUsage[].Quantity" id="PartUsage[]_Quantity" value="" />
Thoughts?
Verify with Firebug that all the post data is being sent from the page via the "Net" tab.
Also, i agree with Kobi: you need to increment the ID's on the cloned elements so they are unique.
I would suggest you look into jQuery for dynamically creating html elements. I have only just started learning jQuery and its very easy.
The following code demonstrates a simple file upload form that allows the user can add more input elements dynamically. Each time the jQuery adds a new input element, i append a chr to the id attribute so they are all unique. Hopefully this helps you:
The script block for the jQuery.. notice the last part is for the ajax animation. The actual copying code is only those 4 lines from $("#moreFiles").click
<script type="text/javascript">
var counter = "oneFile";
$(document).ready(function() {
$("#moreFiles").click(function() {
var newCounter=counter+"1";
$("p#"+counter).after("<p id='"+newCounter+"'><input type='file' name='"+newCounter+"' id='"+newCounter+"' size='60' /></p>");
counter=newCounter;
});
$("#submitUpload").click(function() {
$("#submitUpload").val("Uploading...");
$("img.uploadingGif").show();
});
});
</script>
..and the aspnet markup:
<% string postUrl = Model.PostUrl + (Model.ModelID > 0 ? "/" + Model.ModelID.ToString() : ""); %>
<form id="uploadForm" class="uploadForm" action="<% =postUrl %>"
method="post" enctype="multipart/form-data">
<label>Select file(s) for upload (size must not exceed
<% =Html.Encode(ServiceConstants.MAX_FILE_UPLOAD_SIZE_INBYTES) %> bytes):</label>
<p id="oneFile"><input type="file" name="oneFile" id="oneFile" size="60" /></p>
<% if(Model.MultipleFiles) { %>
<p><a id="moreFiles" href="#">add more files</a></p>
<input id="MultipleFiles" type="hidden" name="MultipleFiles" value="true" />
<% } %>
<p><%--<input id="submitUpload" type="submit" value="Upload" />--%>
<% =Html.InputSubmit("Upload","submitUpload") %>
<% =Html.LoadingImage("uploadingGif") %>
</form>
..this all only boils down to a few lines of html and jQuery.
When you have multiple values on fields with same names, you should be able to see them on the server side using Request.Form.GetValues("key").
You should note that when you clone the nodes, you create copies with the same IDs, which is considered invalid.
Also, you have a for loop there, and I don't quite get what it does (reads the node's name and sets it back - what is the reason for doing that? Should that be var theName = newFields[i].name ?)
I was working with plain HTML when my form worked fine if all the fields were left blank, but it would not submit if I filled out the form.
Later I realized that it was because of a text-field entry 'Email' in which I was entering an email-address containing the character '#'. When I removed the '#', the form started submitting again.
You cannot just aribtrarily add text boxes client-side without having the corresponding server-side controls ready to read the data from the postback. However, you should be able to read the raw data from HttpRequest.Form.
update: oops! it's MVC. I didn't read^H^H^H^H see that. never mind.
-Oisin
Related
In my View i have the following code:
<input type="text" id="createdDate" placeholder="dd/mm/yyyy" />
Download
In my Control i have de following code:
[HttpGet]
public async Task<IActionResult> GetRoomAccessHistory(DateTime createdDate)
{
// TO DO
}
In this particular case, i want to pass the createdDate value that is inside the textbox (createdDate) to my Url.Action(...), so it could be passed as a queryString in my URL.
This action is invoked as a GET request, and in GetRoomAccessHistory control method, i should get my createdDate.
Thank you.
PS
I think the solution should be something like this:
<a href="#Url.Action("GetRoomAccessHistory", "Files", new { createdDate = ??? })" >Download</a>
I have got a possible answer:
<form method="post" enctype="multipart/form-data" asp-action="GetRoomAccessHistory" id="formGetRoomAccessHistory">
...
<button type="button" id="downloadRoomAccessHistory"</button>
</form>
<script>
var form = document.getElementById("formGetRoomAccessHistory");
document.getElementById("downloadRoomAccessHistory").addEventListener("click", function () {
form.submit();
});
</script>
This does exactly what i want and it works, but i was trying to find a more nice solution because my experience in ASP.NET MVC is low.
You're using the wrong tool for the job.
Since the Url.Action() helper runs on the server-side, it has already executed when the page was first loaded, and generated a fixed URL which is inserted into the page's HTML. It cannot know what the user later enters into the textbox.
If you want to capture data which a user has entered, it makes more sense to use a form. In this case I've used the BeginForm tag helper to generate a suitable HTML <form> tag:
<form asp-action="GetRoomAccessHistory" asp-controller="Files" method="get">
<input type="text" id="createdDate" name="createdDate" placeholder="dd/mm/yyyy" />
<input type="submit" value="Download"/>
</form>
When submitted, this will generate a GET request to the GetRoomAccessHistory action's URL, and append createdDate as a querystring variable, using the value from the textbox.
For Get request,try to use window.location.href.
<input type = "text" id="createdDate" placeholder="dd/mm/yyyy" />
<a onclick = "navigate()" >
< input type="button" value='Download' />
</a>
<script type = 'text/javascript' >
function navigate()
{
var createdDate = document.getElementById('createdDate').value;
var url = "/Files/GetRoomAccessHistory?createdDate=" + createdDate;
window.location.href = url;
}
</script>
And your solution could be simplified to
<form method = "get" asp-controller="Files" asp-action="GetRoomAccessHistory" id="formGetRoomAccessHistory">
<input type = "text" name="createdDate" placeholder="dd/mm/yyyy" />
<button type = "button" onclick="myFunction()">Download</button>
</form>
<script>
function myFunction()
{
document.getElementById("formGetRoomAccessHistory").submit();
}
</script>
i'm dynamically pushing data to a link tag and i want to filter the items using a textbox with onkeyup(this).
i want to filter on div_name and recall dynamic function that shows only data for where div_name is..
here's the code i have working with:
<div id="search-area">
<asp:TextBox class="searchInput" id="txtSearch" placeholder="Search for names.." runat="server" onkeyup="filter(this)"></asp:TextBox>
</div>
<div class="row">
<%
using (nlaCareers.applyOnlineJobsEntities db = new nlaCareers.applyOnlineJobsEntities())
{
foreach (var job in db.jobs_with_division_name)
{
%>
<a class="col-md-3 jobs" href="Apply.aspx">
<h3>
<%: job.job_short %>
</h3>
<h4>
<%: job.div_name %>
</h4>
<p>
<%: job.job_long %>
</p>
</a>
<%
}
}
%>
</div>
Normally in such cases there needs to be a second endpoint on the server which returns partial page results (either rendered, or not). A good practice is to have a json endpoint returning only matching rows (as a json array containing data-only).
So on each keyup you will need to perform an ajax call . The response should be iterated and for each element a new dom div class="row" should be created and appended (e.g. using jquery).
Note: when using key-up handlers it would be a good practice to wrap them inside functions like _.debounce(), to avoid performing useless ajax requests.
If you perform the above, you can safely remove the iterate part of your existing code, and just trigger the search when page loads, to also get the initial set of data through ajax.
Update:
As requested I provide an example. I don't have knowlege on asp.net and the semantics of runat="server" so I provide a client-side implementation, using a public json endpoint with user data: https://jsonplaceholder.typicode.com/users. This you will need to create at your server, with custom data.
https://jsfiddle.net/8y68uge1/25/
var filter = _.debounce(function(searchElem) {
console.log("searching for:", searchElem.value)
$.ajax("https://jsonplaceholder.typicode.com/users", {//ajax request
data: {
name_like: searchElem.value
},
dataType: "json"
}).done(function(data) {//When it finishes create and append the rows in the result area
var rows = data.map(function(elem) {
return $("<div class=\"row\"><a><h3>" + elem.name + "</h3><h4>" + elem.username + "</h4><p>" + elem.email + "</p></a></div>")
})
$(".result").empty().append(rows);
});
}, 500);//Perform ajax request only if 500 ms passed after the last keyup.
//Initial rendering
$(document).ready(filter);
I know its a rudimentary questions, but I am out of practice on webforms. I am using Stripe.js for the first time, and want to use it in conjunction with stripe.net to process the client side. Here is the client code:
<%# Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
CodeBehind="StripePage.aspx.cs" Inherits="StripePage.StripePage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
// This identifies your website in the createToken call below
// You need to put your real publish key here.
Stripe.setPublishableKey('pk_test_1nDJ3hA1Mv2Sy9bUoYcBMXmm');
// ...
// I am using jquery to process the payment. It knows what form to
// process it on based on the name 'payment-form'
jQuery(function ($) {
//payment submission
$('#payment-form').submit(function (event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
//if there is a error, it is displayed on the page if there was
//no error this is where it gets sent to the server.
var stripeResponseHandler = function (status, response) {
var $form = $('#payment-form');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
// token contains id, last4, and card type
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
// and submit
$form.get(0).submit();
}
};
});
</script>
<form method="POST" id="paymentForm" runat="server">
<span class="payment-errors" runat="server"></span>
<div class="form-row">
<label>
<span>Card Number</span>
<br />
<input id="number" type="text" data-stripe="number" clientidmode="Static" />
<input type="text" size="20" data-stripe="number" runat="server" />
</label>
</div>
<div class="form-row">
<label>
<span>CVC</span>
<br />
<input type="text" size="4" data-stripe="cvc" runat="server" />
</label>
</div>
<div class="form-row">
<label>
<span>Expiration (MM/YYYY)</span>
<br />
<input type="text" size="2" data-stripe="exp-month" runat="server" />
</label>
<br />
<input type="text" size="4" data-stripe="exp-year" runat="server" />
</div>
<asp:Button ID="submit" ClientIDMode="Static" runat="server" Text="SubmitPayment" OnClick="submit_Click" />
</form>
</asp:Content>
The last call in JS creates a JSON object that I want to know how to get to on the C# page on the button click:
protected void submit_Click(object sender, EventArgs e)
{
....
}
I am wanting to do the javascript implementation to avoid having to do PCI compliance. Am I approaching this incorrectly? Should it be all Stripe.net to process everything, and skip the js entirely? Or if this is right, how can I get the form post data in the button click event?
Thanks for the tips in the comments. After much perusal of the internet and hair pulling, I walked away for a bit and came back with this solution.
Made the button just a standard html input (not the asp:Button)
Got the posted back information that was being sent via the JavaScript in the Page_Load event like so
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
StripeConfiguration.SetApiKey("[API Secret Key");
NameValueCollection nvc = Request.Form;
string amount = nvc["amount"];
var centsArray = amount.Split('.');
int dollarsInCents = Convert.ToInt32(centsArray[0]) * 100;
int remainingCents = Convert.ToInt32(centsArray[1]);
string tokenId = nvc["stripeToken"];
var tokenService = new StripeTokenService();
StripeToken stripeToken = tokenService.Get(tokenId);
var myCharge = new StripeChargeCreateOptions
{
TokenId = tokenId,
AmountInCents = dollarsInCents + remainingCents,
Currency = "usd"
};
var chargeService = new StripeChargeService();
StripeCharge stripeCharge = chargeService.Create(myCharge);
}
}
Seems like using the NameValueCollection (which lives in System.Collections.Specialized namespace) gave me the ability to grab what I needed from the Request.Form by pulling it out via variable name. Since I new the variable names, it was simply a matter of grabbing them and then following the Stripe .NET library documentation to get the token and process the payment.
I want to just post a comment to the answer, but I'm not allowed to yet. So, this isn't really an answer, more of a response to the OP's own findings.
I'm doing the exact same thing, using Stripe.js. I can simply grab stripeToken using Request.Form, and get all other non-c/c-related fields the usual way in the code-behind (e.g. int Total = PaymentTotal.Value;); but what I'm noting isn't so much about grabbing the data, it's that you have to handle it on Page_Load (or during some later point in the page life cycle), because the Submit button's onclick event is never actually fired, since the form is actually submitted using js and not the button.
So, being all literal and kinda answering the original question, you can't actually get the data in the button click event, w/o firing that event manually on postback (I'm surmising).
Hopefully save someone else some time figuring that out if they come here looking to make Stripe and .NET work together.
I have a form that you enter data into and it performs a calculation on it and give an answer. what i want to do is for it to keep the data in the form so that you can quickly repost so that you don't have to change all the data. but I cant keep coming up with the error of it not existing, which I suppose is correct until the form has been posted!
#{
var total = 0m;
var totalMessage = "";
if (IsPost)
{
var age = Request["frmage"].AsInt(0);
var weight = Request["frmweight"].AsDecimal();
var SerCre = Request["frmSerCre"].AsDecimal();
var sexfactor = Request["frmGender"]== "M" ? 1.23m : 1.04m;
total =Convert.ToDecimal ((((140 - age)*weight)* sexfactor )/SerCre ) ;
totalMessage = total.ToString("0.00") + "(ml/min) ";
}
}
<div class="memberRegistration">
<form method="post">
<p>
<label class="formLabel">Age:</label> in years
<input class="formTextField" type="text" name="frmAge" size="3" value="#age"/>
</p>
<p>
<label class="formLabel">Weight:</label> in Kg (1st = 6.35kg)
<input class="formTextField" type="text" name="frmWeight" value="#weight"/>
</p>
<p>
<label class="formLabel">Serum Creatinine:</label> in μmol/L
<input class="formTextField" type="text" name="frmSerCre" value="#SerCre"/>
</p>
<p>
<label class="fieldLabel">Gender:</label>
<select name="frmGender" id="select" value="#sexfactor">
<option value="M">Male</option>
<option value="F">Female</option>
</select>
</p>
<p><input type="submit" value="Calculate" /></p>
</form>
<p>Calculated creatinine clearance <b>#totalMessage</b></p>
</div>
Try this
var age = 0;
if (IsPost)
{
age = Request["frmage"].AsInt(0);
}
<input class="formTextField" type="text" name="frmAge" size="3" value="#age"/>
But normally it would be better to use a model to hold your values, then in your controller you pass those values back again to your form
Enable the ViewState of the page and controls and also use aspx control, not HTML.
I don't thing that i realy understand the Question because the default thing is that the web page keeps it's view state so the data will still be the same after the post back but here's the solution :
you can simply use ASP Controls because it keep it's view state
or you can give each control of them it's value in the C# , you can assign to each control it's value back
Hope I Helped
Since you are using ASP.NET MVC Razor, what you can do is, do not submit the form using <input type="submit" value="Calculate" /> , instead change it to a simple button like
<input type="button" value="Calculate" onclick="javascript:Submitform();" />
and submit the form using Jquery POST.e.g. like below
function SubmitForm(){
var formData = $("form").serialize() ;
var submitUrl = 'yourURL' ;
$.ajax({
type : 'POST' ,
url : submitUrl ,
data : formData ,
success : function (data ){ alert ("Request successful") ;}
error : function (jqXHR, status , errorthrown) { alert ("error Occured");}
});
}
<% using (Html.BeginForm("SearchByZip", "Dealer", new { zip = ""}, FormMethod.Get))
{ %>
<div>
<input type="text" class="padLeft" name="Zip" id="Zip" style="width: 200px" />
<input type="submit" class="btnFind" value="Find" />
</div>
<% } %>
This gives me the url "Dealer/SearchByZip?Zip=12345"
I would like to end up with this: "Dealer/Zip/12345"
(if I manually type in the url "Dealer/Zip/12345" it returns the right results, but when I click in submit it comes up with "Dealer/SearchByZip?Zip=12345"
What am I missing?
routes.MapRoute(
"DealerSearchByZip",
"Search/Zip/{zip}",
new { Controller = "Dealer", action = "SearchByZip", zip = "" }
);
This is happening because "Zip" is an input field in your form, not route data. So, when the page is rendered it creates a url using the default route ("DealerSearchByZip" route wasn't matched because Zip wasn't given as route data).
You could accomplish this via javascript, by updating the "action" attribute on the form when the "zip" field is updated.
Example using jQuery:
$('input[name=Zip]').update(function(){
$('form').attr('action', 'Dealer/Zip/' + $(this).val());
});
Or, since Zip is the only value you're worried about,
$('form').submit(function(){
window.location = 'Dealer/Zip/' + $('input[name=Zip]').val();
});