I am using Razor Pages. I have a form that allows you to either buy or sell. I need to change a value of the OrderType field in the OrderPlacement model, depending on whether the user buys or sells. I accomplish this using javascript.
<input type="hidden" asp-for="#Model.OrderPlacement.OrderType" />
<input class="btn-primary" type="button" value="Buy" asp-page-handler="Buy" onclick="SubmitBuyOrder();" />
<input class="btn-primary" type="button" value="Sell" asp-page-handler="Sell" onclick="SubmitSellOrder();" />
And here is my JavaScript:
function SubmitSellOrder() {
document.getElementById('OrderPlacement_OrderType').value = 'Sell';
document.getElementById('OrderForm').submit();
}
function SubmitBuyOrder() {
document.getElementById('OrderPlacement_OrderType').value = 'Buy';
document.getElementById('OrderForm').submit();
}
Here are my backend methods:
public async Task<IActionResult> OnPostBuyAsync()
{
OrderPlacementResponse response = new OrderPlacementResponse();
try
{
if (!ModelState.IsValid)
return Page(); //Display User Errors
else
{
//Do Some Stuff
}
}
catch (Exception ex)
{
//TODO: Log Errors
//TODO: Redirect to Error Page
return RedirectToPage("/Error"); //show errors
}
}
public async Task<IActionResult> OnPostSellAsync()
{
OrderPlacementResponse response = new OrderPlacementResponse();
try
{
if (!ModelState.IsValid)
return Page(); //Display User Errors
else
{
//Do Some Stuff
}
}
catch (Exception ex)
{
//TODO: Log Errors
//TODO: Redirect to Error Page
return RedirectToPage("/Error"); //show errors
}
}
The backend methods are not being hit. But I see the javascript methods being hit.
I tried using the regular method of having the buttons submit directly where type="submit". But I still need to have the OrderType change depending on which button is pressed, so I still need the type to remain as "button" and the onclick to call the javascript methods.
Also, I cannot set this value (OrderType) in the backend because there is validation that is run before the backend method is hit.
What is wrong with my existing code, that it will not submit?
Here is a working demo you could follow:
View
#page
#model IndexModel
<form id="OrderForm" method="post">
<input type="hidden" asp-for="#Model.OrderPlacement.OrderType" />
<input class="btn-primary" type="submit" value="Buy" asp-page-handler="Buy"
onclick="SubmitBuyOrder(event)" />
<input class="btn-primary" type="submit" value="Sell" asp-page-handler="Sell"
onclick="SubmitSellOrder(event);" />
</form>
#section Scripts
{
<script>
function SubmitSellOrder(e) {
e.preventDefault();
document.getElementById('OrderPlacement_OrderType').value = 'Sell';
var url = document.activeElement.getAttribute("formaction");
document.getElementById('OrderForm').action=url;
document.getElementById('OrderForm').submit();
}
function SubmitBuyOrder(e) {
e.preventDefault();
document.getElementById('OrderPlacement_OrderType').value = 'Buy';
var url = document.activeElement.getAttribute("formaction");
document.getElementById('OrderForm').action=url;
document.getElementById('OrderForm').submit();
}
</script>
}
Be sure your backend contains such property with [BindProperty] attribute:
[BindProperty]
public OrderPlacementResponse OrderPlacement { get; set; }
Besides, you can also combine to one function like below:
#page
#model IndexModel
<form id="OrderForm" method="post">
<input type="hidden" asp-for="#Model.OrderPlacement.OrderType" />
<input class="btn-primary" type="submit" value="Buy" asp-page-handler="Buy" />
<input class="btn-primary" type="submit" value="Sell" asp-page-handler="Sell" />
</form>
#section Scripts
{
<script>
$("#OrderForm").on("submit",function(e){
e.preventDefault();
var orderType= $(this).find("input[type=submit]:focus").val();
document.getElementById('OrderPlacement_OrderType').value = orderType;
var url = document.activeElement.getAttribute("formaction");
document.getElementById('OrderForm').action=url;
document.getElementById('OrderForm').submit();
})
</script>
}
Related
im using Razor pages and in my page model i have empty list. I need it to by filled by user. And i do not know how many items there will be. Currently im using post methods to add inputs to my page like this:
public async Task OnPostAddLicence()
{
await SetDials();
LicenceList.Add(new Licence());
}
public async Task OnPostRemoveLicence(int index)
{
await SetDials();
ModelState.Clear();
LicenceList.RemoveAt(index);
}
problem with this aproach is that it reloads the page and scroll to TOP of the page.
Unfortunately i did not find any way to scroll back on where i was. And because its razor pages maintain scroll position is not working.
so i would like to add these item dynamicaly with javascript. i tried using this:
<div id="divCont">
<div>
<input type="text" class="form-control" asp-for="Salaries[0].HoursWorked" placeholder="Odpracovaných hodin">
<input type="button" onclick="AddTextBox()" value="Add" />
</div>
</div>
<script type="text/javascript">
function GetDynamicTextbox(value) {
return '<div><input type="text" name="txttest" style="width:200px;" asp-for="Salaries[0].HoursWorked" /><input type="button" onclick="RemoveTextBox(this)" value="Remove" /></div>';
}
function AddTextBox() {
var div = document.createElement('DIV');
div.innerHTML = GetDynamicTextbox("");
document.getElementById("divCont").appendChild(div);
}
function RemoveTextBox(div) {
document.getElementById("divCont").removeChild(div.parentNode.parentNode);
}
</script>
but it is not binding the value to the list.
And all others methods that i could find online are not working with razor pages but just mvc
Do you mean you cannot bind data to input?If so,sometimes asp-for cannot work,you can have a try to change asp-for="Salaries[0].HoursWorked" to
id="Salaries_#(0)__HoursWorked"
name="Salaries[#(0)].HoursWorked"
value=#Salaries[0].HoursWorked
Here is a example to show how to bind data without asp-for:
<input type="text" asp-for="#Model.Locations[0].Street" /></td>
<input type="text" id="Locations_0__Street" name="Locations[0].Street" value=#Model.Locations[0].Street />
result:
Here is a worked demo to show the binding:
Page:
<form method="post">
<input asp-for="#Model.postdata.data[0].id" class="form-control" />
<input id="postdata_data_0__name" name="postdata.data[0].name" value="#Model.postdata.data[0].name" class="form-control" />
<div>
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
PageModel:
public class TestModel : PageModel
{
[BindProperty]
public Postdata postdata{ get; set; }
public IActionResult OnGet()
{
List<TestDT> data = new List<TestDT>();
TestDT testDT = new TestDT { id = 1, name = "test1" };
TestDT testDT2 = new TestDT { id = 2, name = "test2" };
data.Add(testDT);
data.Add(testDT2);
postdata = new Postdata();
postdata.data = data;
return Page();
}
public IActionResult OnPost()
{
return Page();
}
}
Result:
So basically i am trying to implement 2checkout in my website and i have done everything from documentation but i get this error: TwoCheckoutException: Bad request - parameter error. I tried checking and playing with private/public keys and id but when i change them it says "authoization error" so i am sure they are okay. I read about addresses and everything and i have changed them but still not working.
Here is my full code:
#{
ViewData["Title"] = "Test";
}
<script type="text/javascript" src="https://www.2checkout.com/checkout/api/2co.min.js"></script>
<h2>Test</h2>
<form id="myCCForm" action="/Home/SubmitCard" method="post">
<input name="token" type="hidden" value="" />
<div>
<label>
<span>Card Number</span>
<input id="ccNo" type="text" value="" autocomplete="off" required />
</label>
</div>
<div>
<label>
<span>Expiration Date (MM/YYYY)</span>
<input id="expMonth" type="text" size="2" required />
</label>
<span> / </span>
<input id="expYear" type="text" size="4" required />
</div>
<div>
<label>
<span>CVC</span>
<input id="cvv" type="text" value="" autocomplete="off" required />
</label>
</div>
<input type="submit" value="Submit Payment" />
</form>
<script type="text/javascript">
// Called when token created successfully.
var successCallback = function (data) {
var myForm = document.getElementById('myCCForm');
// Set the token as the value for the token input
myForm.token.value = data.response.token.token;
// IMPORTANT: Here we call `submit()` on the form element directly instead of using jQuery to prevent and infinite token request loop.
myForm.submit();
};
// Called when token creation fails.
var errorCallback = function (data) {
if (data.errorCode === 200) {
alert("Error 200");
// This error code indicates that the ajax call failed. We recommend that you retry the token request.
} else {
alert(data.errorMsg);
}
};
var tokenRequest = function () {
// Setup token request arguments
var args = {
sellerId: "901417674",
publishableKey: "309FC596-8380-4B6F-B269-3E157A5A5D0B",
ccNo: $("#ccNo").val(),
cvv: $("#cvv").val(),
expMonth: $("#expMonth").val(),
expYear: $("#expYear").val()
};
// Make the token request
TCO.requestToken(successCallback, errorCallback, args);
};
$(function () {
// Pull in the public encryption key for our environment
TCO.loadPubKey('sandbox');
$("#myCCForm").submit(function (e) {
// Call our token request function
tokenRequest();
// Prevent form from submitting
return false;
});
});
</script>
and here is server side code:
public IActionResult SubmitCard()
{
TwoCheckout.TwoCheckoutConfig.SellerID = "901417674";
TwoCheckout.TwoCheckoutConfig.PrivateKey = "4E704021-B233-435F-A904-47B2620B9E66";
TwoCheckout.TwoCheckoutConfig.Sandbox = true;
try
{
TwoCheckout.AuthBillingAddress Billing = new TwoCheckout.AuthBillingAddress();
Billing.addrLine1 = "123 Main Street";
Billing.city = "Townsville";
Billing.zipCode = "43206";
Billing.state = "Ohio ";
Billing.country = "USA";
Billing.name = "Joe Flagster";
Billing.email = "Ex#a.com";
Billing.phoneNumber = "065";
TwoCheckout.ChargeAuthorizeServiceOptions Customer = new TwoCheckout.ChargeAuthorizeServiceOptions();
Customer.total = 1;
Customer.currency = "USD";
Customer.merchantOrderId = "12";
Customer.billingAddr = Billing;
Customer.token = Request.Form["token"];
TwoCheckout.ChargeService Charge = new TwoCheckout.ChargeService();
var result = Charge.Authorize(Customer);
return View("Success", result);
}
catch(TwoCheckout.TwoCheckoutException ex)
{
return View("Error", ex.ToString());
}
}
and here is all info from my sandbox:
You may need to update your site settings for sandbox from Site Management -> Site Settings and Turn to On for Demo Settings and check again
May it helps you
HTML
<input type="Submit" value="Add" id="btn1"/>
<input type="Submit" value="Add2" id="btn2"/>
Jquery
$("#btn1").click(function () {
$("[id*=btn2]").click();
});
Controller
[httpPost]
Public ActionResult MyAction(){
//some code
return view();
}
Here, how can I differentiate, whether I have directly clicked the btn2 or it is coming from btn1?
Keep an hidden html tag for keeping track.
Here, get the value from #ViewBag.hdnIsButton1Clicked for [HtpGet]/initial request for the View.
<input type="hidden" value="#ViewBag.hdnIsButton1Clicked" id="hdnIsButton1Clicked" name="hdnIsButton1Clicked" />
Set the value of the hidden field and also prevent the default behaviour of submit action.
Jquery
$("#btn1").click(function (event) {
$("#hdnIsButton1Clicked").val("1");
event.preventDefault()
$("[id*=btn2]").click();
})
Add a parameter to get the hidden value and set the viewbag data to be 0 again
Controller
[httpPost]
Public ActionResult MyAction(string hdnIsButton1Clicked){
if(hdnIsButton1Clicked == "1")
{
//user clicked button 1
}
#ViewBag.hdnIsButton1Clicked = "0";
return view();
}
Note - you can set the hidden value true/false. I have given the idea to solve it.
Use code like this :
Changed the button from submit to button. Now HTML will look like this:
<form id="myForm">
....
....
<input type="button" value="Add" id="btn1"/>
<input type="button" value="Add2" id="btn2"/>
</form>
Then the script:
var btn1_cliked = false;
$("#btn1").click(function () {
$(this).attr("name","btn1");
btn1_cliked = true;
$("[id*=btn2]").click();
});
$("#btn2").click(function () {
if(btn1_clicked)
$("button[name='btn1']").removeAttr("name","btn1");
$(this).attr("name","btn2");
$("#myForm").submit();
});
In controller:
Check if $_POST['btn1'] //then btn1 clicked
else // then btn2 clicked
Try this
var flag = 0;
$("#btn1").click(function() {
flag = 1;
$("[id*=btn2]").click();
});
$("#btn2").click(function(e) {
if (flag == 1) {
flag = 0;
alert("from btn1");
} else {
alert("from btn2");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="Submit" value="Add" id="btn1" />
<input type="Submit" value="Add2" id="btn2" />
I use the following code for edit operation and I've button in the edit screen which I want that it will be enabled when the edit is success
how can I do that?
This is the edit operation
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="UserId,FirstName,LastName,Email,Phone,PhoneWork,WorkingAt")] User user)
{
if (ModelState.IsValid)
{
db.Entry(user).State = EntityState.Modified;
db.SaveChanges();
}
return View(user);
}
This is the button
#using (Html.BeginForm("check", "User"))
{
<input type="submit" id="btn" value="check" />
<span id='result'></span>
}
First You have to disable your button on load
#using (Html.BeginForm("check", "User"))
{
<input type="submit" id="btn" value="check" disabled />
<span id='result'></span>
}
and on your edit button write function onclick=enable(); add jquery
<script type="text/javascript">
function enable() {
var btn = document.getElementById("btn");
btn.disabled = false;
}
</script>
Just make sure your use button tag with type submit
<button type="submit" id="btn" value="check">Save</button>
This is what i m doing for my buttons, just use javascript to achieve.
<script>
$(document).ready(function () {
$(document).on('invalid-form.validate', 'form', function () {
var button = $(this).find('button[type="submit"]');
setTimeout(function () {
button.removeAttr('disabled');
}, 1);
});
$(document).on('submit', 'form', function () {
var button = $(this).find('button[type="submit"]');
setTimeout(function () {
button.attr('disabled', 'disabled');
}, 0);
});
});
</script>
Let me know if that helps.
Right now, the code below upon submit, first inserts a file THEN submits the form. This is problematic - I need for it to verify the form was successfully posted to Amazon S3 then insert the (token) file so it can link to it.
I basically need to reverse SubmitFile and InsertFile, but I'm not sure how to have (If form successfully sent, then run another javascript function). See very bottom for an attempt...Is this possible?
<apex:pageMessages id="pageErrors"></apex:pageMessages>
<form name="s3Form" action="https://s3.amazonaws.com/mybucket" method="post" enctype="multipart/form-data">
<input type="hidden" name="key"/>
<input type="hidden" name="AWSAccessKeyId" value="{!key}"/>
<input type="hidden" name="policy" value="{!policy}"/>
<input type="hidden" name="signature" value="{!signedPolicy}"/>
<input type="hidden" name="acl" value="private"/>
<input type="hidden" name="x-amz-meta-FileId" value="{!File__c.id}"/>
<input type="hidden" name="x-amz-meta-OrderId" value="{!OrderId}"/>
<input type="hidden" name="x-amz-meta-CustomerId" value="{!CustomerId}"/>
<input type="hidden" name="success_action_redirect" value="{!serverUrl}{!OrderId}"/>
<apex:pageBlock title="New File Upload" mode="maindetail" tabStyle="File__c"> <!-- rendered="{!open}"-->
<apex:pageBlockSection title="File Information" columns="2" collapsible="false" showHeader="false">
<apex:pageBlockSectionItem >
<apex:outputLabel value="Select File" for="selectFile"/>
<input id="selectedFile" type="file" size="25" name="file" onChange="setFileName(this.value)"/>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
<apex:pageBlockButtons location="bottom">
<input class="btn" type="button" value="Upload File" onClick="checkFile();return false;"/>
<input class="btn" type="button" value="Cancel" onClick="cancelFile();return false;"/>
<input class="btn" type="button" value="Complete Order" onClick="completeFile();return false;"/>
</apex:pageBlockButtons>
</apex:pageBlock>
<apex:outputText styleClass="footer" value="Please click Complete Order when all the required files are uploaded. Thank you." />
</form>
<apex:form id="sfForm"><!-- rendered="{!open}"-->
<apex:inputHidden id="hiddenServerURL" value="{!serverURL}"/>
<apex:inputHidden id="fileName" value="{!fileName}"/>
<apex:inputHidden id="contentType" value="{!contentType}"/>
<apex:inputHidden id="fileType" value="{!fileType}"/>
<apex:actionFunction name="insertFile" action="{!insertFile}" oncomplete="submitFile();return false;"/>
<apex:actionFunction name="completeOrder" action="{!completeOrder}"/>
<script type="text/javascript">
var sendFile = false;
document.getElementById('{!$Component.hiddenServerURL}').value = '{!$Api.Enterprise_Server_URL_140}';
function setFileName(file) {
var f = file.replace(/\\/g, "");
f = f.replace(/C\:fakepath/g, ""); <!--Required for IE8-->
document.s3Form.key.value = "{!CustomerName}/{!OrderName}/" + f;
document.getElementById('{!$Component.fileName}').value = f;
suffix = f.lastIndexOf(".") + 1;
contentType = f.slice(suffix);
document.getElementById('{!$Component.contentType}').value = contentType;
}
function setFileType(type) {
document.getElementById('{!$Component.fileType}').value = type;
}
function checkFile() {
if (document.s3Form.file.value=="") {
alert("Please, select a file.");
return false;
}
else if (document.s3Form.fType.value=="--None--") {
alert("Please, select a file type.");
return false;
}
else {
alert("Uploading...Please click OK and wait for page to refresh.");
insertFile();
sendFile = true;
}
}
function submitFile() {
if(sendFile = false) {
return false;
}
else {
document.s3Form.submit();
}
}
function completeFile() {
completeOrder();
}
</script>
</apex:form>
In the controller (extension):
//SF File insert on an object (passed from page)
public PageReference insertFile() {
this.file.Name = fileName;
this.file.Type__c = fileType;
this.file.Content__c = contentType;
insert this.file;
return null;
}
Here is the javascript section i tried to alter, but i can't find anything after extensive searches on if this works...
function checkFile() {
if (document.s3Form.file.value=="") {
alert("Please, select a file.");
return false;
}
else if (document.s3Form.fType.value=="--None--") {
alert("Please, select a file type.");
return false;
}
else {
alert("Uploading...Please click OK and wait for page to refresh.");
document.s3Form.submit({
success: function(){
alert("Testing!");
insertFile();
},
});
}
}
So if I'm understanding you correctly you want to:
Validate file
Upload file to amazon s3
Save file token to salesforce
Not to throw a wrench in your plans but you might try completing the whole routine in apex. Here's some pseudo code. Salesforce also has developed a toolkit for working with Amazon S3 so you shouldn't have to develop everything from scratch.
Visualforce Page:
<apex:page controller="MyController">
<apex:form>
<apex:inputFile value="{!file.body}" filename="{!file.name}"/>
<apex:commandButton value="Submit" action="{!submitFile}"/>
</apex:form>
</apex:page>
Apex Controller:
public class MyController {
public Document file { get; set; } { file = new Document(); } // dummy object for storing binary file data
public void submitFile() {
if(!validateFile())
return;
String s3Token = submitToS3();
if(s3Token != null) {
File__c newFile = new File__c(name = file.name, s3_token__c = s3Token);
insert newFile;
}
}
}
+1 on doing the work in Apex as opposed to Javascript.
But to continue with a potentially successful hack, try using apex:actionPoller for your form submit. When it wakes up it checks for success on your file insert. If after a few polls you still don't have success then flag a timeout.
Javascript novelties in Visualforce can be perilous, unless time is not a factor for you. Best exhaust Visualforce/Apex options first and only then venture into custom JavaScript in special cases or for lightweight UI tweaks, imo.