Laravel: Update value on button click for approved - laravel-5.4

Hello I'm still new to laravel and I've searching the web for almost 3 hours about this issue I have I tried many things but it didn't work.
So basicly I have a page with a button, when I click that button "Approved" I want to update the value from 0 to 1 (the column is of type boolean). This is my controller:
public function update(Request $request, SubmitApplication $submitApplication)
{
$submitApplication->update(['approved', 1]);
return back();
}
This is page section with the button it's in the folder trainings and has the name "show.blade.php":
<form class="btn-group" action="{{ route('requisitions.update', ['id' => $requisition->id]) }}" method="post">
{{ method_field('PATCH') }}
{{ csrf_field() }}
<button type="submit" class="btn btn-success btn-xs">Approved</button>
</form>
I don't see any errors after clicking the button

I am guessing you have a modal name submitApplication, if so change your controller to this,
public function update(Request $request)
{
submitApplication::where('id',$request->get('id'))->update(['approved'=>true]);
return redirect()->back();
}

Related

Angular 13 - How to open form without button and the button click

My angular component has a tree and several nodes. When I double click on a node the click event runs a web api and retrieves data for an id that will be used to create a dynamic form using npm package: #rxweb/reactive-dynamic-forms. Once the data request is 'completed' a button appears and when clicked it opens the form with appropriate fields for the id selected. I would like to eliminate the need for this secondary button click. I've tried several suggestions but just cannot get anything to work.
I'm using Infragistics controls and bootstrap for the form.
html:
<div class="column-layout my-pane-layout">
<div *ngIf = "isShowFormButton" >
<button #open igxButton="raised" igxRipple="white" (click)="form.open()">Run</button>
<igx-dialog #form [closeOnOutsideSelect]="true" >
<igx-dialog-title>
<div class="dialog-container">
<igx-icon>vpn_key</igx-icon>
<div class="dialog-title">Form</div>
</div>
</igx-dialog-title>
<form class="input-group-form" [formGroup]="dynamicForm.formGroup" (ngSubmit)="onSubmit()">
<div class="container">
<div class="controls" viewMode="horizontal" [rxwebDynamicForm]="dynamicForm" [uiBindings]="uiBindings">
</div>
<button igxButton="raised" type="submit" igxRipple class="button" [disabled]="!dynamicForm.formGroup.valid">
<igx-icon>
directions_run
</igx-icon>
<span>Submit</span>
</button>
</div>
</form>
<div igxDialogActions>
<!-- <button igxButton (click)="form.close()">CANCEL</button> -->
<button igxButton (click)="form.close()">Submit</button>
</div>
</igx-dialog>
</div>
<h6 class="h6">
Levels
</h6>
<igx-tree #tree class="tree" selection="None" >
<igx-tree-node *ngFor="let level1 of myData" [data]="level1">
{{ level1.Name }}
<igx-tree-node *ngFor="let level2 of level1.levels" [data]="level2">
{{ level2.Name }}
<igx-tree-node *ngFor="let level3 of level2.levelplus" [data]="level3" (dblclick)="onDoubleClick($event,level3)">
{{level3.Name }}
</igx-tree-node>
</igx-tree-node>
</igx-tree-node>
</igx-tree>
</div>
XYZ.component.ts:
export class XYZComponent implements OnInit {
#ViewChild('form') dialog: IgxDialogComponent;
myData: any[];
public tree: IgxTreeComponent;
public selectedNode;
public ID: number = 2;
isShowRunButton: boolean = false;
public dynamicForm!: DynamicFormBuildConfig;
public dynamicFormConfiguration!: DynamicFormConfiguration;
constructor(private dynamicFormBuilder:RxDynamicFormBuilder){}
ngOnInit() {
populate tree with data here ...
}
public onDoubleClick(event,node) {
console.log(node);
event.stopPropagation();
this.runParameters(node.Id);
}
public runParameters(Id) {
this.aSer.getApi(Id).subscribe({next:(data: any[]) => {this.myData = data;},
error: err => {console.log(err); },
complete: () => {
this.dynamicForm =
this.dynamicFormBuilder.formGroup(this.myData,this.dynamicFormConfiguration);
this.isShowFormButton = true;
//this.dialog.open();
}
});
}
public onSubmit() {
console.log(this.dynamicForm.formGroup);
this.isShowFormButton= false;
//this.dialog.open();
}
}
If I uncomment out the 'this.dialog.open()' the code throws the following error:
TypeError: Cannot read properties of undefined (reading 'open')
Many postings say that I need to use a #ViewChild but it seems that it cannot find that reference : #ViewChild('form') dialog: IgxDialogComponent;
Any help would be much appreciated. Code works fine with the 'Run' button click but I want to eliminate that extra step.

Laravel pass id to my sql on button click from view

I am trying to activate or deactivate the products for a form using $product->status
The active button shows if $product->status is 0 and
The deactive button shows if $product->status is 1
I want to toggle the value of $product->status in the mysql database every time I click on the button
<form action="{{route('invetory.create')}}" method="POST">
#csrf
<table class="table table-bordered" id="dynamicTable">
<tr>
<th>item</th>
<th>tax</th>
<th>Action</th>
</tr>
#forelse($products as $product)
<input type="text" name="item" value="{{$product->id}}
class="form-control" hidden />
<td>
<input type="text" name="item" value="{{$product->item}}
class="form-control" />
</td>
<td>
<input type="text" name="tax" value="{{$product->tax}}
class="form-control" />
</td>
#if($product->status =='0')
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">active</button>
</td>
#else
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-danger remove-tr deactive_btn">Deactive</button>
</td>
#endif
</table>
</form>
here i have given the route i have used
web.php
Route::post('/update', 'App\Http\Controllers\InventoryController#update')>name('invetory.update');
here i have added the controler i have used
InventoryController.php
public function update(Request $REQUEST){
dd($REQUEST->all());
Inventory::update( $REQUEST->invetory as $key => $value);
return redirect()->action([InventoryController::class, 'index']);
}
i am geting 500 error when i click button
You can achieve this using POST request which will refresh the page each time you toggle a product or you can use AJAX to do the change asynchronously. Using Javascript and AJAX would be the preferred way so you don't lose selected filters, pagination etc.
You don't need external packages to implement that, you can use JavaScript's fetch method. Also, instead of having 2 separate functions and routes, I would suggest having one route that would toggle the product's status, i.e. if it is active, make it inactive and vice versa. That method by definition should be a POST request, by I prefer doing GET requests for this in order to avoid CSRF protection and use middleware to protect the request.
Here is the complete code.
Register a web route that toggles the state inside web.php
Route::get('projects/toggle', [ProjectController::class, 'toggle'])->name('projects.toggle');
Implement the toggle method in ProjectController.php
public function toggle(Request $request) {
$project = Project::find($request->project_id);
$project->status = !$project->status;
$project->save();
return response()->json(['status' => (int) $project->status]);
}
Notice that I am returning a json response which includes the new project status. We will use this in the JavaScript code to dinamically update the column where the status is shown.
Finally, in the blade file, when iterating through the projects, the button click calls a function that will do the AJAX request. Notice that I am also adding an id attribute to the columns that contains the status so I can access it dinamically in order to update it.
#foreach($projects as $project)
<tr>
<td>{{$project->title}}</td>
<td id="project-status-{{$project->id}}">{{$project->status}}</td>
<td><button onClick="toggleStatus('{{$project->id}}')">Toggle</button></td>
</tr>
#endforeach
In this same file, we add the following JavaScript code. It accepts project_id as parameter which is passed from the button click, makes the ajax request to backend which updates the status and then updates the appropriate DOM element to show the new status.
function toggleStatus(project_id) {
fetch("{{ route('projects.toggle') }}?project_id=" + project_id)
.then(response => response.json())
.then(response => {
document.querySelector("#project-status-" + project_id).innerHTML = response.status;
})
}
As I mentioned, you can use multiple options in the JavaScript part. Instead of calling a function you can register an event listener to each button, but this approach with function call is a bit quicker. Also, I am passing the project_id as GET parameter, you can define the route to contain it as route parameter, but then you'll need to do some string replacements in order to do in dinamically in JavaScript. All in all, the proposed is a good solution that will serve your purpose.
p.s. For stuff like this, LiveWire is a perfect fit.
Using dd (e.g. in your controller) will throw a 500 error. It literally stands for "dump and die".
check you routes in form use{{route('invetory.create')}}
and in routes you given inventory.update
public function Stauts(Request $request)
{
$product= Product::findOrFail($request->id);
$product->active == 1 ? $product->active = 0 : $product->active = 1 ;
$product->update();
return response()->json(['status' => true,'msg' => 'Staut updated']);
}
in blade use ajax
<script>
$(document).on('click', '.status-product', function (e) {
e.preventDefault();
var product_id = $(this).data('id');
var url ="{{ route('product.status') }}";
$.ajax({
type: "post",
url: url,
data: {
'_token': "{{csrf_token()}}",
'id': product_id
},
success: function (data) {
if (data.status == true) {
$('#deactive_ajax').show();}
}
})
})
</script>
Route::post('product/stauts/', [productController::class,'Stauts'])->name('product.Stauts');
First of all
Using a form with tables is not ideal and some browsers already made changes to prevent that.
Secondly
The best way is as DCodeMania said, the ajax request is the best way to solve this, I'll just modify his answer a bit and use Patch instead of PUT, so it'll look like this:
$(document).on('click', '.active_btn', function(e) {
e.preventDefault();
let id = $(this).data('id');
$.ajax({
url: '{{ route("products.update") }}',
method: 'PATCH',
data: {
id: id,
_token: '{{ csrf_token() }}'
},
success: function(response) {
console.log(response);
}
});
});
and you'll only be needing one button so no need to make the check for $product->status he added, just a single button for the toggle will make your code cleaner.
As for using PATCH instead of PUT, because you're only updating one single column and not the whole thing getting updated, and no need for the status parameter, you'll just reverse what's inside the database
$product = Product::find($request->id);
Product::where('id', $product->id)->update([
'status' => $product->status ? 0 : 1,
]);
You'll also need one button with different text based on status
like this
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">{{ $product->status == 1 ? 'deactivate' : 'activate' }}</button>
</td>
I did it this way and it works for me
First in view does this
<td>
#if ($producto->estado == '1')
<a href="{{ url('/status-update-producto', $producto->id) }}"
class="btn btn-success" id="btn_estado">Activo</a>
#else
<a href="{{ url('/status-update-producto', $producto->id) }}"
class="btn btn-danger" id='btn_estado'>Inactivo</a>
#endif
</td>
Controller
function updateStatusProducto($id)
{
//get producto status with the help of producto ID
$producto = DB::table('productos')
->select('estado')
->where('id', '=', $id,)
->first();
//Check producto status
if ($producto->estado == '1') {
$estado = '0';
} else {
$estado = '1';
}
//update producto status
$values = array('estado' => $estado);
DB::table('productos')->where('id', $id)->update($values);
return redirect()->route('productos.index');
}
Route
Route::get('/status-update-producto/{id}', [ProductoController::class, 'updateStatusProducto']);
You could add some data attributes to your buttons, and use them in js to send an ajax request
#if ($product->status =='0')
<td>
<button type="button" class="btn btn-success toggle-tr" data-product="{{ $product->id }}" data-status="{{ $product->status }}">active</button>
</td>
#else
<td>
<button type="button" class="btn btn-danger toggle-tr" data-product="{{ $product->id }}" data-status="{{ $product->status }}">Deactive</button>
</td>
#endif
document.querySelectorAll('.toggle-tr').forEach(el => el.addEventListener('click', e => {
const product = e.target.dataset.product;
const status = e.target.dataset.status == 0 ? 1 : 0;
// send ajax or fetch request passing in product_id. If we're going with a RESTful approach,
axiox.patch(`/products/${product}`, { status })
.then(res => { ... })
.catch(err => { ...});
}));
You can use jQuery ajax here:
Pass product id in data-id attribute
#if($product->status =='0')
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-success remove-tr active_btn">active</button>
</td>
#else
<td>
<button type="button" data-id="{{ $product->id }}" class="btn btn-danger remove-tr deactive_btn">Deactive</button>
</td>
#endif
then use ajax:
$(document).on('click', '.active_btn', function(e) {
e.preventDefault();
let id = $(this).data('id');
$.ajax({
url: '{{ route("products.update") }}',
method: 'PUT',
data: {
id: id,
status: 1,
_token: '{{ csrf_token() }}'
},
success: function(response) {
console.log(response);
}
});
});
$(document).on('click', '.deactive_btn', function(e) {
e.preventDefault();
let id = $(this).data('id');
$.ajax({
url: '{{ route("products.update") }}',
method: 'PUT',
data: {
id: id,
status: 0,
_token: '{{ csrf_token() }}'
},
success: function(response) {
console.log(response);
}
});
});
Now you can handle the request in the controller.

Can't get input value with Twig

Hello I was trying to pass some arguments but I don't know how to get value of input using twig here is my code :
okey first of all im displaying the blog details using this detailsaction which also rendering a form to add comments to the blog ;
public function detailsAction(Request $request,Blog $blog){
$user=$this->getUser();
if($user==null)
return $this->redirectToRoute('fos_user_security_login');
$add_comment = new CommentaireBlog();
$em = $this->getDoctrine()->getManager();
$comments = $em->getRepository(CommentaireBlog::class)->findByBlog($blog);
$add_comment->setBlog($blog);
$add_comment->setUser($user);
$add_comment->setDate( new \DateTime());
$form = $this->createFormBuilder($add_comment)
->add('contenu', TextareaType::class)
->getForm();
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$add_comment = $form->getData();
$em = $this->getDoctrine()->getEntityManager();
$em->persist($add_comment);
$em->flush();
return $this->redirectToRoute('blog_details', array('id' => $blog->getId()));
}
}
return $this->render('blog/details.html.twig', array(
'form' => $form->createView(),
'comment' => $add_comment,
'blog' => $blog,
'comments'=>$comments,
));
}
twig page:
{{ form_start(form) }}
<div class="row form-group">
<div class="col col-md-3"><label class=" form-control-label">Votre Commentaire </label></div>
<div class="col-12 col-md-9"> {{ form_widget(form.contenu, { 'attr': {'class': 'form-control'} }) }}<small class="form-text text-muted"></small></div>
<button type="submit" class="btn btn-default">Envoyer</button>
<div class="col-12 col-md-9">
</div>
</div>
{{ form_end(form) }}
now what i want to do is that after someone add a comment and its(racist/verbual abuse..) an other user can report the comment and a mail will be sent so i used reportAction which take three arguments the reason the message and comment id
public function reportAction($msg,$type,$id)
{
}
i still didnt write inside it cause first of all i need to the value of inputs so i went to the twig page and i made this little form to get inputs but idk how to get the value
here is the form :
<div class="modal-body">
<form id="lala" method="GET">
<label for="cars">Reason:</label>
<select id="reportreason">
<option value="Inappropriate Content">Inappropriate Content</option>
<option value="Spam">Spam</option>
<option value="Racism">Racism</option>
<option value="Nudity">Nudity</option>
<option value="Other">Other</option>
</select>
<div class="form-group">
<label for="message-text" class="col-form-label">Message:</label>
<textarea id="reportmessage" class="form-control" id="message-text"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<a id="reportlink" href="{{ path('comment_report', { 'msg': form.vars.data.reportmessage ,'type': form.vars.data.reportreason, 'id': comment.id }) }}" type="button" class="btn btn-primary">Send message</a>
</div>
this is yml file :
blog_details:
path: /{id}/details
defaults: { _controller: "BlogBundle:Blog:details" }
methods: [GET, POST]
comment_report:
path: /{msg}/{type}/{id}/report
defaults: { _controller: "BlogBundle:Blog:report" }
methods: [GET, POST]
but im getting this error now :
Neither the property "reportmessage" nor one of the methods "reportmessage()", "getreportmessage()"/"isreportmessage()" or "__call()" exist and have public access in class "BlogBundle\Entity\CommentaireBlog".
so how can i get get the value of the inputs using twig ?
Twig Object Syntax https://twigfiddle.com/01iobj
Effectively the twig error message is saying that in your path() arguments, you are passing an object without an associated key as {value} The correct syntax would be {key: value} or [value], resembling a JSON syntax.
{
"key1": { "key1a": "value1a" },
"key2": ["value2"],
"key3": "value3"
}
Result
$_GET = array(
'key1' => array('key1a' => 'value1a'),
'key2' => array('value2'),
'key3' => 'value3'
);
A different approach
Looking at what you want to do, you need to refactor your approach.
First change your controller pathing for ONLY the comment.
blog_details:
path: /{id}/details
defaults: { _controller: "BlogBundle:Blog:details" }
methods: [GET, POST]
comment_report:
path: /{comment}/report
defaults: { _controller: "BlogBundle:Blog:report" }
methods: [POST]
Next create a form instance for your modal, this will allow you use the FormInstance for rendering and validating the submitted form elsewhere. Ensuring that all of the validation occurs and you're not having to update different scripts for the same form.
/* /src/Form/CommentReportForm.php */
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type as Form;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
class CommentReportForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('reason', Form\ChoiceType::class [
'choices' => [
'Inappropriate Content' => 'Inappropriate Content',
'Spam' => 'Spam',
'Racism' => 'Racism',
'Nudity' => 'Nudity',
'Other' => 'Other'
]
])
->add('message', Form\TextType::class, [
'constraints' => [
new Assert\Length(['min' => 10]),
new Assert\NotBlank(),
],
]);
}
public function getBlockPrefix()
{
return 'report_comment_form';
}
}
Next, update your Controller actions accordingly.
public function detailsAction(Request $request, Blog $blog)
{
if (!$user = $this->getUser()) {
//this should be handled in your firewall configuration!!!!
return $this->redirectToRoute('fos_user_security_login');
}
$em = $this->getDoctrine()->getManager();
$add_comment = new CommentaireBlog();
$add_comment->setBlog($blog);
$add_comment->setUser($user);
$add_comment->setDate(new \DateTime());
$form = $this->createFormBuilder($add_comment)
->add('contenu', TextareaType::class)
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
//Symfony form sets values for the model by_reference
$em->persist($add_comment);
$em->flush();
return $this->redirectToRoute('blog_details', array('id' => $blog->getId()));
}
/*
* create the report form
*/
$reportForm = $this->createForm(\App\Form\CommentReportForm::class);
$reportForm->handleRequest($request);
return $this->render('blog/details.html.twig', array(
'form' => $form->createView(),
'comment' => $add_comment,
'blog' => $blog,
'comments'=> $em->getRepository(CommentaireBlog::class)->findByBlog($blog),
/*
* give the report form a different name in twig
*/
'report_form' => $reportForm->createView(),
));
}
public function reportAction(Request $request, CommentaireBlog $comment)
{
$reportForm = $this->createForm(\App\Form\CommentReportForm::class);
$reportForm->handleRequest($request);
/** #var array|string[message, reason] */
$reportData = $reportForm->getData();
/*
array( 'reason' => 'value', 'message' => 'value' )
*/
dump($reportData);
if ($reportForm->isSubmitted() && $reportForm->isValid()) {
//send email
//redirect to success message
}
//display an error message
}
Lastly update your view to support the new form in your modal.
<div class="modal-body">
{{ form_start(report_form, { action: path('comment_report', { comment: comment.id }) })
{{ form_label(report_form.reason) }}
{{ form_widget(report_form.reason) }}
<div class="form-group">
{{ form_label(report_form.message) }}
{{ form_widget(report_form.message) }}
</div>
{{ form_end(report_form) }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Send message</button>
</div>
As a recommendation, I strongly urge you to record the report submissions in the database, to function as a case log and status of the reports. My approach will get you most of the way there, you would just need to create your App\Entity\CommentReport entity, with an optional association to the CommentaireBlog entity. Which would be passed to the form and adding the data_class to the form options resolver, mimicking what you have done in your other database forms.
I don't know why you wrote your path call like that, but there should not be any round brackets about the variables you want to use in your route. The following code should work:
<a
href="{{ path('comment_report', { 'msg': form.reportmessage.value ,'type': form.reportreason.value, 'id': comment.id }) }}"
type="button"
class="btn btn-primary">
Send message
</a>

how to delete user from return in controller

route not working, where should I put #csrf and #method('DELETE')? because it does not delete the user. before the problem happens, #csrf and #method('DELETE') was in blade view. But when I put #csrf and #method('DELETE') in return it shows an error.
$employees = DB::table('users')->leftjoin('roles', 'users.role_id', '=', 'roles.id')->leftjoin('supervisors', 'users.manager_id', '=', 'supervisors.id')
->select(['users.id','users.name','users.department','users.email','users.leaves_available','roles.name_role','supervisors.name_supervisor']);
return Datatables::of($employees)
->addColumn('action', function ($employees) {
return '<form action="'.route('employee.destroy', $employees->id).'" method="post">
<button type:"submit" class="btn btn-sm btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>';
})->make(true);
in the form I use route('employee.destroy', $employee->id) then the parameter will be http://localhost:8000/employee/1 and I want the user got delete.
EmployeeController.php
public function destroy($id)
{
DB::table('users')->delete($id);
return redirect()->route('home')
->with('success','Employee have been deleted');
}
This is my web.php
Route::get('employee/{id}', 'EmployeeController#destroy');
I expect the destroy function will run and redirect back to home. But what I get is :
The POST method is not supported for this route. Supported methods:
GET, HEAD, PUT, PATCH, DELETE.
Change the route from get to post. Like this
Route::post('employee/{id}', 'EmployeeController#destroy');
Because, you are using post method in your form but your route is in get. Both need to be same.

taking input from button in thymeleaf

I am displaying a form to user with some details and then user clicks approve and reject. In the backend, I want to take this in one property - userAction, which can be "approve" or "reject".
How can I add input to the buttons that user clicks? And then this input is part of the object requestDto.
<form th:action="#{/mission/store/{uuid}(uuid=${uuid})}" th:object="${requestDto}" method="post" class="mission_form">
<div class="wizard-header">
<h3 class="wizard-title">
Approve Mission
</h3>
<h5>Should you chose to accept this mission, press approve.</h5>
</div>
<div class="wizard-footer">
<!--<div class="pull-right">-->
<input type='button' class="btn btn-success" name='approve' value='Approve' />
<!--</div>-->
<div class="pull-left">
<input type='button' th:field="*{}" class='btn btn-danger' name='previous' value='Decline' />
</div>
<div class="clearfix"></div>
</div>
</form>
First define a proper DataTransferObject:
public class MyRequestDto {
private String userAction;
// don't forget getters and setters
}
Then add a object of that class to your model
// if you are return a M&V-object:
ModelAndView mv = new ModelAndView("viewName")
ModelAndView.addObject("requestDto", new MyRequestDto());
// if you define a Model-Object as input-parameter:
Model.addAttribute("requestDto", new MyRequestDto());
Define a form like this (I used button-elements). The point is not to use the th:field attribute:
<form th:action="...." method="POST" th:object="${requestDto}">
<button name="userAction" value="approve" >Approve</button>
<button name="userAction" value="reject" >Reject</button>
</form>
Recieve the DataTransferObject by adding this to your controllers input-paramters (the controller that handels the post request):
... #Valid RequestDto requestDto, BindingResult bindingResult, ....
Now you can access requestDto's userAction-Attribute. The value is approve if you click the first button and it is reject if you click the second button. First you can check if there are binding errors by checking bindingResults.hasErrors().