Problem invoking widget's action method in NopCommerce - nopcommerce

I am trying to develop a widget in NopCommerce 4.3. I need to Post data from widget public view to the controller's Action method with Ajax. The problem is that when the call is made from the view, Product page is called instead of my widget view. This is the VS output:
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2.0 POST https://localhost:44331/aliento-de-ogro application/x-www-form-urlencoded 292298. Excepción producida: 'System.ArgumentException' en System.Private.CoreLib.dll. Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executing endpoint 'Nop.Web.Controllers.ProductController.ProductDetails (Nop.Web)' Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Route matched with {action = "ProductDetails", controller = "Product", area = ""}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult ProductDetails(Int32, Int32) on controller Nop.Web.Controllers.ProductController (Nop.Web). Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor: Information: Executing ViewResult, running view ProductTemplate.Simple. Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor: Information: Executed ViewResult - view ProductTemplate.Simple executed in 411.9849ms.
This is how widget's view looks like:
<form id="AjaxForm" method="post">
<input type="hidden" id="productId" value=#ViewBag.sku />
<input type="hidden" id="input_elem" name="image" />
<div class="col-md-9">
<div id="ErrorAlert" class="alert alert-danger" style="display:none" role="alert">
Error en los datos enviados!
</div>
<div id="ExitoAlert" class="alert alert-success" style="display:none" role="alert">
Datos recibidos correctamente!
</div>
</div>
<button class="btn btn-success" id="SubmitBtn" type="submit">Save photo</button>
</form>
$.ajax({
type: "post", // Verbo HTTP
url: "#Url.Action("TakePhoto", "Photo")",
dataType: "application/json",
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken: "]').val() },
data: JSON.stringify(
{
// Datos / Parámetros
ProductId: $("#productId").val(),
Role: role, //$("#role").val(),
ExpressionName: expressionName, //$("#expressionName").val(),
Photo: $("#photo").attr('src')
}),
contentType: "application/json; charset=utf-8"
})
.done(function (result) {
alert(result.Message);
}
})
.fail(function (xhr, status, error) {
})
.always(function () {
});
return false;
});
Asp.net backend is receiving "application/x-www-form-urlencoded" instead of "application/json". Why? Is this the reason because my widget's controller is not reached? Why Nop.Web.Controllers.ProductController.ProductDetails (Nop.Web)' is invoked?

It doesn't seem you're receiving the request from the Ajax call. Instead you're receiving the request from some form in the page.
This seems clear since you're receiving the request from a different endpoint and with a different content type. Since it seems you have an image in your form the multipart request is logical in that scenario.
My suggestions are:
Check your page and look for a multipart form in it. Some problem handling events could make that form to fire instead of your code. Are there nested forms?
Enable the request history in Chrome and the preserve log option. Get a verbatim copy of the request. Check the Url.
In .NET, retrieve a verbatim copy of the received request. Check the Url.
Set a breakpoint in your Javascript code and see if it is being called at all.
I think this will help you.

Related

How do I mark data context as changed?

I have a page that handles some query data from the url, as in localhost/home?foo=bar.
It then sends a JSON to some server somewhere. That much works.
With iron-router, I handle a form submission like so: Router.go('home', {}, {query: queryObjectVar}), which also works.
So when you submit the form with foo="somethingelse" you end up in localhost/home?foo=somethingelse, the page mostly doesn't reload because of meteor magic thus looking really fast, and the JSON is sent with foo=somethingelse, and all is well.
However if you're in localhost/home?foo=var and then you go to the same exact route with Router.go(...), query included, the url doesn't change, and the page does not send the JSON thing. Which in most cases is fine, since technically nothing changed so nothing should need to be done. However, I want it to behave as if the url changed.
How do I do that?
Currently I have the template hooked up to the query like so:
Router.route('home', {
data: function() { return this.params.query }
})
I'm not sure if this is what you want, but you could change the route by making an extra navigation.
Often, after submitting the form, you want the user to know that the form was received or processed somehow.
I would suggest to make an extra route that only handles the processing, something like /home/process. Have the event handler on form submit navigate to the process route. The action for the route sends the json file based on this.params.query.
After the json was sent (I used console.log but better approach would be Meteor.call('here_I_will_sent_json', this.param.query), render a template that let's the user know that the data was sent. And now the trick: have a link or button in the template that navigates to /home or whatever you want the user to direct to.
Templates.
<template name="main">
<div>Sample application</div>
{{> yield}}
</template>
<template name="mainPage">
<div>Main page</div>
Home
</template>
<template name="home">
<div>Home page</div>
{{> form}}
</template>
<template name="form">
<form id="myForm" method="get">
<input type="text" name="foo">
<input type="submit" value="Save">
</form>
</template>
<template name="finishedSending">
<div>finishedSending!</div>
go to main page
</template>
Javascript:
Router.configure({
layoutTemplate: 'main'
});
Router.route('mainPage', {path: '/'});
Router.route('home', {path: '/home'});
// Extra route just for processing the submitted form
Router.route('process', {
path: '/home/process',
data: function() {
return this.params.query
},
action: function() {
// Here you send the json or do whatever you need to process.
// Best to have some Meteor method do the actual processing.
// You could use a callback if processing takes some time.
console.log('Send the json content based on: ', this.params.query);
this.render('finishedSending');
}
});
if (Meteor.isClient) {
Template.main.events({
'submit #myForm': function (e) {
e.preventDefault();
var fieldValue = event.target.foo.value;
Router.go('process', {} , {query: {foo: fieldValue}})
}
});
}

Polymer POST http://localhost:3000/ 404 (Not Found)

I am trying to create a charge for Stripe using node.js. So I have followed Firebase method to see if I could get this working:
For clarity, I have left out the polymer elements imports. Assume all is well.
/charge.html:
<dom-module id="stripe-charge">
<template>
<script>
var firebaseStripe = new Firebase('https://blahblah.firebaseio-demo.com/');
firebaseStripe.set({
var stripe = require("stripe")("sk_test_blahblah");
var stripeToken = request.body.stripeToken;
var charge = stripe.charges.create({
amount: 1000, // amount in cents, again
currency: "gbp",
source: stripeToken,
description: "Example charge"
}, function(err, charge) {
if (err && err.type === 'StripeCardError') {
// The card has been declined
}
});
</script>
</template>
<script>
Polymer({
is: 'stripe-charge',
});
</script>
</dom-module>
index:
<section data-route="charge">
<stripe-charge></stripe-charge>
</section>
routing.html:
page('/charge', function () {
app.route = 'charge';
});
page({
hashbang: true
});
form:
<form is="iron-form" id="myForm" action="http://localhost:3000/#!/charge" method="post">
<input type="hidden" is="iron-input" id="amount" name="amount" bind-value="{{total}}">
<input type="hidden" id="stripeToken" name="stripeToken"/>
<input type="hidden" is="iron-input" id="stripeEmail" name="stripeEmail" bind-value="{{emailInput}}"/>
</form>
<paper-button class="fullBtn" id="customButton" on-click="stripe">
<iron-icon icon="icons:credit-card"></iron-icon>
Pay
</paper-button>
When I press the pay button, fill out card details etc, then hit the Strip pay button, I get the green but when it goes to the charge page, I get POST http://localhost:3000/ 404 (Not Found) Somehow it's not going to the page. Any ideas? I feel there will be more errors but for now, I want to get that page. Firebase issue?
Change your url be a true path, not a hash location:
<form is="iron-form" id="myForm" action="http://localhost:3000/charge" method="post">
You need to run a server that accepts the post and then makes a call to Stripe with your private key, you cannot run Stripe as a pure client-only process.
The first step in the browser calls stripe and packages up the supplied credit card information, but then you need to provide that token to your server. Otherwise anyone could submit charges on your behalf, including refunds!

MVC + Forms: Post error

I am getting the following error whenever I try to do a simple form post in my MVC website.
Either BinaryRead, Form, Files, or InputStream was accessed before the internal storage was filled by the caller of HttpRequest.GetBufferedInputStream.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: Either BinaryRead, Form, Files, or InputStream was accessed before the internal storage was filled by the caller of HttpRequest.GetBufferedInputStream.
My sample form and actions are pretty basic...
#using (Html.BeginForm("Create", "Form"))
{
<div class="row action">
<div class="row">
First name: <input type="text" name="fname"><br>
Last name: <input type="text" name="lname"><br>
</div>
<input type="submit" id="save" class="btn" value="Save"/>
<input type="button" id="cancel" class="btn" value="Cancel"/>
</div>
}
And my Controller action is even more basic...
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
// TODO: Add insert logic here
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Please share your route.config file that might help solving this problem.
Just in case also try removing the perimeters from Html.BeginForm() remove the name of the action and controller. As MVC has strong naming systems because of which we don't need to add that info.
if above doesn't solve your issue Share your route file.

Not able to post form in Adode CQ5

I am a newbie in AdobeCQ5. I am facing some trouble in posting form. Here is my Structure -
/apps/<myproject>/components/mytestcomponent
mytestcomopnent.jsp has following code -
<form id="myForm" action="<%=resource.getPath()+".html" %>">
<input type="text" id="t1" class="input-small" placeholder="Temprature F" />
<input type="text" id="t2" class="input-small" placeholder="Temprature C" readonly/>
<button type="button" id="cbtn" class="btn">Convert</button>
</form>
<script>
$(document).ready(function() {
$('#cbtn').click(function () {
var URL = $("#myForm").attr("action");
alert(URL);
var t1=$("#t1").val();
var t2=$("#t2").val();
$.ajax({
url: URL,
data:{'t1':t1},
type:"post",
success: function(data, status) {
$("#t2").val(data);
},
error: function( xhr, txtStat, errThrown ) {
alert("ajax error! " + txtStat + ":::" + errThrown);
}
});
});
});
</script>
This is giving my response code 200 (Success) but the output is not desired. My mycomponent.POST.jsp has following code -
<%
// TODO add you code here
String t1=request.getParameter("t1");
%>
<%= t1 %>
It gives the following output
Content modified /content/imobile/en/jcr:content/social.html
Status
200
Message
OK
Location /content/imobile/en/_jcr_content/social.html
Parent Location /content/imobile/en/_jcr_content
Path
/content/imobile/en/jcr:content/social.html
Referer http://example.comt:4502/content/imobile/en.html
ChangeLog
<pre></pre>
Go Back
Modified Resource
Parent of Modified Resource
Please help to resolve this.
The JSP file handling the POST method for your component should be named POST.jsp rather than mycomponent.POST.jsp.
Please notice that if you intercept all POST requests to your component, you won't be able to edit it on the author instance using a dialog (as the dialog simply POSTs data to the component URL). To avoid it, consider using a custom selector (like form). Your form should look be declared like this:
<form id="myForm" action="${resource.path}.form.html">
and the script handling POST request should be called form.POST.jsp.
The second important thing is that you should use Java classes rather than JSP files to store business logic. In this case it means that the form.POST.jsp script can be replaced with a Sling servlet declared as follows:
#SlingServlet(
resourceTypes="myproject/components/mytestcomponent",
methods="POST",
selectors="form")

KnockoutJS, updating ViewModel after ajax call

I am using Knockout and the Knockout Mapping plugin.
My MVC3 Action returns a View and not JSON directly as such I convert my Model into JSON.
This is a data entry form and due to the nature of the system validation is all done in the Service Layer, with warnings returned in a Response object within the ViewModel.
The initial bindings and updates work correctly its the "post-update" behavior that is causing me a problem.
My problem is after calling the AJAX POST and and receiving my JSON response knockout is not updating all of my bindings... as if the observable/mappings have dropped off
If I include an additional ko.applyBindings(viewModel); in the success things do work... however issues then arise with multiple bindings and am certain this is not the correct solution.
This is the HTML/Template/Bindings
<!-- Start Form -->
<form action="#Url.Action("Edit")" data-bind="submit: save">
<div id="editListing" data-bind="template: 'editListingTemplate'"></div>
<div id="saveListing" class="end-actions">
<button type="submit">Save Listings</button>
</div>
</form>
<!-- End Form -->
<!-- Templates -->
<script type="text/html" id="editListingTemplate">
<div class="warning message error" data-bind="visible: Response.HasWarning">
<span>Correct the Following to Save</span>
<ul>
{{each(i, warning) Response.BusinessWarnings}}
<li data-bind="text: Message"></li>
{{/each}}
</ul>
</div>
<fieldset>
<legend>Key Information</legend>
<div class="editor-label">
<label>Project Name</label>
</div>
<div class="editor-field">
<input data-bind="value: Project_Name" class="title" />
</div>
</fieldset>
</script>
<!-- End templates -->
And this is the Knockout/Script
<script type="text/javascript">
#{ var jsonData = new HtmlString(new JavaScriptSerializer().Serialize(Model)); }
var initialData = #jsonData;
var viewModel = ko.mapping.fromJS(initialData);
viewModel.save = function ()
{
this.Response = null;
var data = ko.toJSON(this);
$.ajax({
url: '#Url.Action("Edit")',
contentType: 'application/json',
type: "POST",
data: data,
dataType: 'json',
success: function (result) {
ko.mapping.updateFromJS(viewModel, result);
}
});
}
$(function() {
ko.applyBindings(viewModel);
});
</script>
And this is the response JSON returned from the successful request including validation messages.
{
"Id": 440,
"Project_Name": "",
"Response": {
"HasWarning": true,
"BusinessWarnings": [
{
"ExceptionType": 2,
"Message": "Project is invalid."
}, {
"ExceptionType": 1,
"Message": "Project_Name may not be null"
}
]
}
}
UPDATE
Fiddler Demo Is a trimmed live example of what I am experiencing. I have the Project_Name updating with the returned JSON but the viewModel.Response object and properties are not being updated through their data bindings. Specifically Response.HasWarning().
I've changed back to ko.mapping.updateFromJS because in my controller I am specifically returning Json(viewModel).
Cleaned up my initial code/question to match the demo.
I guess Response is reserved, when I change "Response" to "resp", everything went fine. See http://jsfiddle.net/BBzVm/
Should't you use ko.mapping.updateFromJSON on your success event? Chapter Working with JSON strings on Knockout Mapping site says:
If your Ajax call returns a JSON string (and does not deserialize it into a JavaScript object), then you can use the functions ko.mapping.fromJSON and ko.mapping.updateFromJSON to create and update your view model instead.

Resources