Slugs not working in Forms with GET method - symfony

This is my routing:
myapp_upgradeAccount:
path: /upgradeAccount
defaults: { _controller: myapp:UpgradeAccount:index }
myapp_checkUsernameForUpgrade:
path: /upgradeAccount/check/{username}
defaults: { _controller: myapp:UpgradeAccount:checkUsername }
methods: [GET]
and this is my form
<form method="get" action="upgradeAccount/check">
<label for="username">Insert your username:</label>
<input name="username" type="text">
<input id="chech-username-for-upgrade" class="green" type="submit" value="Check">
...
But everytime I submit the form I get this error:
No route found for "GET /upgradeAccount/check"
The problem is that when I submit the form, I get the following URL:
http://localhost/app_dev.php/upgradeAccount/check?username=123
when i think I should be getting
http://localhost/app_dev.php/upgradeAccount/check/123
If I trz the latter manually, it works allright. What am I missing?

This is the way HTML forms work.
From w3.org:
get: With the HTTP "get" method, the form data set is appended to the
URI specified by the action attribute (with a question-mark ("?") as
separator) and this new URI is sent to the processing agent.
To do what you want to do keeping the GET method, you have to define your route as:
myapp_checkUsernameForUpgrade:
path: /upgradeAccount/check
defaults: { _controller: myapp:UpgradeAccount:checkUsername }
methods: [GET]
And in your controller, you access the query string parameter with:
if(!is_null($this->getRequest()->get('username'))
{
//Do your stuff
}
EDIT:
If you want your user to be redirected to a url formatted as upgradeAccount/check/{username}, you can either do it with JavaScript (as suggested in #usoban answer) or inside the controller using Redirect:
//path: /upgradeAccount/check
public function check()
{
if(!is_null($this->get('request')->request->get('username')))
return $this->redirect($this->generateUrl('myapp_checkUsernameForUpgrade', array('username' => $this->get('request')->request->get('username'))));
//By default, return the view with your form asking the username
return $this->render('AcmeHelloBundle:Hello:index.html.twig');
}
//path: /upgradeAccount/check/{username}
public function checkUsername($username)
{
//Do some fun stuff with $username coming from the url
}
Then in your view, the form signatures becomes:
<form method="post" action="upgradeAccount/check">
<label for="username">Insert your username:</label>
<input name="username" type="text">
<!-- additionnal fields -->
<input id="chech-username-for-upgrade" class="green" type="submit" value="Check">
</form>
And your route:
myapp_check:
path: /upgradeAccount/check
defaults: { _controller: myapp:UpgradeAccount:check }
methods: [POST]
myapp_checkUsernameForUpgrade:
path: /upgradeAccount/check/{username}
defaults: { _controller: myapp:UpgradeAccount:checkUsername }
methods: [GET]

You need to generate routes that take parameters.
so you would need to do
<form method="get" action="{{path('your_route_name', {username:'usernmae'})">
However this obviously won't quite work for you since you do not know the username until they enter it. You could look into the FOSJsRoutingBundle but this will require javascript. Not the best solution, but it will work. Otherwise you will need to remove the username parameter

As #cheesemacfly mentioned, that is how forms work :)
To get it woking myself, I used some javascript. Let's assume you're using jQuery:
<form method="get" action="upgradeAccount/check/___username___" id="my_form">
...
<input name="username" type="text" id="username">
$(document).ready(function(){
$('#my_form').submit(function(evt){
var username = $('#username').val(),
action = $(this).attr('action').replace(/___username___/g, username);
if (/* empty or whatever 'validation' */) {
evt.preventDefault(); // stop the form from submitting
return false;
}
$(this).attr('action', action);
return true;
});
});

Related

How to dynamically set 'was-validated' class on form to show validation feedback messages with angular 5 after submit

I am using a template based form in angular. I also use bootstrap (v4) and I wish to show some validation messages when the form was submitted.
This is my form:
<form [ngClass]="{'was-validated': wasValidated}">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" class="form-control" [(ngModel)]="category.name" #name="ngModel" required maxlength="100"/>
<div *ngIf="name.invalid" class="invalid-feedback">
<div *ngIf="name.errors.required">
Name is required.
</div>
</div>
</div>
<button type="submit" class="btn btn-success" (click)="save()">Save</button>
</form>
My component looks as follows:
category: Category;
wasValidated: boolean = false;
ngOnInit() {
this.reset();
}
save() {
this.wasValidated = true;
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
}
reset() {
this.wasValidated = false;
this.category = {} as Category;
}
This works, but I have a feeling it's overly complex and more like a workaround rather than the right way. What is the best way to accomplish this?
Note: the class was-validated must be present on the form element in order to show the div with class invalid-feedback. I'm using this: https://getbootstrap.com/docs/4.0/components/forms/#validation
Note 2: I have currently no mechanism yet to prevent form submission on error. I'd like to know a good solution for that as well!
With the answer from #Chellappan V I was able to construct the solution I wanted.
I have applied to following changes:
First added #form="ngForm" to the form tag in the template. Secondly I changed the ngClass expression to reference the submitted state of the form, rather than referring to a boolean which was set to true manually when form was submitted. Last but not least I pass the form in the submit method on the save button.
<form novalidate #form="ngForm" [ngClass]="{'was-validated': form.submitted}">
<!-- form controls -->
<button type="submit" class="btn btn-success" (click)="submit(form)">Save</button>
</form>
In the component I injected the template variable in the component with #ViewChild.
#ViewChild("form")
private form: NgForm;
The submit method now takes a form parameter of type NgForm which is used to check if the form was valid before sending a request to the backend:
submit(form: NgForm) {
if (form.valid) {
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
} else {
this.notificationService.add(notifications.validation_errors);
}
}
Finally the reset method resets the form and the model so it can be re-entered to submit a next instance:
reset() {
this.form.resetForm();
this.category = {} as NewCategoryDto;
}

pass values from view to controller

in my html5 page there is a search textbox with a haperlink. when i click on hyperlink value does not goes to controller. i can not use form because on this page i am already using a form.
<input type="text" name="searchval"/>
Go!
and in controller
function user()
dim val as string = Request("searchval")
but searchval always return nothing even i put some text in textbox. Please help
Hyperlinks do not submit forms. You need a form tag and a submit button.
<form action="/users" method="POST">
<input type="text" name="searchval"/>
<input type="submit" value="Go!" />
</form>
You also need to make sure your VB.NET method is routed to appropriately by the form action and is actually a controller action:
Function User() As ActionResult
when you click on hyperlink call ajax function.
function Searchfunction() {
var searchValue = $("#searchval").val();
$.ajax({
url: '#Url.Action("Action", "Controller")',
data: { "searchval": searchValue },
success: function (result) {
$('#dvSearch').html(result);
}
});
}

How to redirect #Url.Action

I have link with parameter:
[http://localhost:8545/Admin/Agent/ManageUser?agentId=3230][1]
After change language new link:
[http://localhost:8545/Admin/Agent/ManageUser][2]
have error beacause haven't ?agentId=3230
i use :<input type="hidden" name="ReturnUrl" value="#Url.Action(null)" />
i don't know edit #Url.Action(null), please help me. thanks!
try this input
<input type="hidden" name="ReturnUrl" value="#Url.Action(ViewContext.RouteData.Values["controller"].ToString(), ViewContext.RouteData.Values["action"].ToString(), new { agentId = Request.QueryString["agentId"] })" />
Firs parameter if Url.Action is controller name, second parameter is action name and last one the routeValues can you add query strings in URL.
If you just need to return the user to the same URL he was before changing the language, just keep the full URL in your hidden input as follows:
<input type="hidden" name="ReturnUrl" value="#Request.Url.AbsoluteUri" />
Also (assuming your ChangeLanguage method is accessibly using the same host-name), you could simply do:
public ActionResult ChangeLanguage(string lang)
{
// something like...
// Session["Lang"] = lang;
return Redirect(Request.UrlReferrer.ToString());
}

Symfony2 <a> link with 'post' or 'delete' or 'put' method

I'd like to generate a url with a 'PUT' or 'POST' method requirement, via a <a href> link.
Since I use a framework server-side, I use a fake form to do this - example with PUT method :
<form action="someActionUri" method="post">
<input type="hidden" name="_method" value="PUT" />
<input type="submit" value="GO PUT" />
</form>
But, I'd like to use a simple <a> link :(
An anchor <a href="#"> will always use a GET request. There is no way to modify that. But, it is possible to fake a PUT or DELETE request using Symfony.
Symfony Forms will fake the verb by adding a hidden field to forms.
<input type="hidden" name="_method" value="PUT" />
Then internally it checks if the verb is POST, checks for the _method parameter and changes the verb from POST to PUT. This only works for HTML forms using the POST method.
The same can be done for GET verbs, but it requires using an Event Listener. Here is an example:
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernel;
class VerbListener
{
public function onKernelRequest ( GetResponseEvent $event )
{
$request = $event->getRequest();
if ( HttpKernel::MASTER_REQUEST === $event->getRequestType()
&& $request->getMethod() === 'GET' )
{
if ( $request->query->get('_method') === 'PUT' ) {
$request->setMethod( 'PUT' );
}
}
}
}
And the service must be registered with a higher priority than the router_listener service, which matches the route to a controller.
services:
acme.verb.listener:
class: Acme\Bundle\Listener\VerbListener
tags:
- { name: kernel.event_listener,
event: kernel.request,
method: onKernelRequest,
priority: 100 }
The link can now be generated with the _method parameter
In the routing file :
entity_edit:
pattern: /entity/{id}/edit
defaults: {_controller: MyBundle:Entity:put}
My controller (with fosRest):
/**
* #Rest\View()
*/
public function putAction(Request $request, $id)
{
...code ...
}
My TWIG:
<a href="{{ path('entity_edit', {'id': data.id} ) }}" >Edition</a>
Even if I like #twifty response, I think that is a bit overkill to listen to every single request just to adapt some of them.
It's much simpler to output a form instead of your link, so instead of link, you can simply use:
<form action="{{ path('my_route_with_put_method') }}" method="POST">
<button>link</button>
<input type="hidden" name="_method" value="PUT">
</form>
You just need to pay attention, because you're using a block element (form) instead of an inline element (a), but you can easily go around that (for example including other inline elements inside the form or using CSS)

ASP.Net MVC 4 Form with 2 submit buttons/actions

I have a form in ASP.Net and razor.
I need to have two ways of submitting said form: one that goes through the Edit action, and another that goes through the Validate action.
How should I go about doing this?
I don't mind using JavaScript for this.
EDIT:
Using the custom attribute I get this error.
The current request for action 'Resultados' on controller type 'InspecoesController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Validar(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
System.Web.Mvc.ActionResult Resultados(System.Collections.Generic.ICollection1[Waveform.IEP.Intus.Server.Web.ViewModels.ResultadoViewModel]) on type Waveform.IEP.Intus.Server.Web.Controllers.InspecoesController
That's what we have in our applications:
Attribute
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
Actions decorated with it:
[HttpParamAction]
public ActionResult Save(MyModel model)
{
// ...
}
[HttpParamAction]
public ActionResult Publish(MyModel model)
{
// ...
}
HTML/Razor
#using (#Html.BeginForm())
{
<!-- form content here -->
<input type="submit" name="Save" value="Save" />
<input type="submit" name="Publish" value="Publish" />
}
name attribute of submit button should match action/method name
This way you do not have to hard-code urls in javascript
You can do it with jquery, just put two methods to submit for to diffrent urls, for example with this form:
<form id="myForm">
<%-- form data inputs here ---%>
<button id="edit">Edit</button>
<button id="validate">Validate</button>
</form>
you can use this script (make sure it is located in the View, in order to use the Url.Action attribute):
<script type="text/javascript">
$("#edit").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Edit","MyController")");
form.submit();
});
$("#validate").click(function() {
var form = $("form#myForm");
form.attr("action", "#Url.Action("Validate","MyController")");
form.submit();
});
</script>
If you are working in asp.net with razor, and you want to control multiple submit button event.then this answer will guide you. Lets for example we have two button, one button will redirect us to "PageA.cshtml" and other will redirect us to "PageB.cshtml".
#{
if (IsPost)
{
if(Request["btn"].Equals("button_A"))
{
Response.Redirect("PageA.cshtml");
}
if(Request["btn"].Equals("button_B"))
{
Response.Redirect("PageB.cshtml");
}
}
}
<form method="post">
<input type="submit" value="button_A" name="btn"/>;
<input type="submit" value="button_B" name="btn"/>;
</form>
Here is a good eplanation:
ASP.NET MVC – Multiple buttons in the same form
In 2 words:
you may analize value of submitted button in yout action
or
make separate actions with your version of ActionMethodSelectorAttribute (which I personaly prefer and suggest).
With HTML5 you can use button[formaction]:
<form action="Edit">
<button type="submit">Submit</button> <!-- Will post to default action "Edit" -->
<button type="submit" formaction="Validate">Validate</button> <!-- Will override default action and post to "Validate -->
</form>
<input type="submit" value="Create" name="button"/>
<input type="submit" value="Reset" name="button" />
write the following code in Controler.
[HttpPost]
public ActionResult Login(string button)
{
switch (button)
{
case "Create":
return RedirectToAction("Deshboard", "Home");
break;
case "Reset":
return RedirectToAction("Login", "Home");
break;
}
return View();
}
We can have this in 2 ways,
Either have 2 form submissions within the same View and having 2 Action methods at the controller but you will need to have the required fields to be submitted with the form to be placed within
ex is given here with code Multiple forms in view asp.net mvc with multiple submit buttons
Or
Have 2 or multiple submit buttons say btnSubmit1 and btnSubmit2 and check on the Action method which button was clicked using the code
if (Request.Form["btnSubmit1"] != null)
{
//
}
if (Request.Form["btnSubmit2"] != null)
{
//
}

Resources