I need your help I'm making a shopping cart in laravel with vuejs.
I have the following problem I am new to vuejs I am inserting products from a component A where is my form in vue I insert it but I have no response in my component B where is my table where the products are registered, be careful if you add the detail is that I have to reload the page to see that the number of products increased.
I am using EventBus from vuejs
I hope you can help me thanks for any help
this is my form
<form method="post" v-on:submit.prevent>
<input :value="csrf" type="hidden" name="_token" >
<input :model="ProductSearch.id" name="id" type="hidden" class="form-control input-lg">
<input :value="ProductSearch.name" name="name" type="hidden" class="form-control input-lg">
<input :value="ProductSearch.sale_price" name="precio" type="hidden" class="form-control input-lg">
<input :value="1" name="cantidad" type="number" class="form-control input-lg" min="1" style="text-align:center" >
<button v-on:click="addproduct" class="btn btn-info btn-block" name="btnAccion" value="Agregar" type="submit"> Add</button>
</form>
This is my method
addproduct: async function () {
axios.post('sales/item', {
id: this.id,
name: this.name,
precio: this.precio,
cantidad: this.cantidad,
})
.then(function(response){
EventBus.$emit('agregado', response.data)
})
.catch(error => {
console.log(error.response);
});
}
this is my table where I reflect my result.
<tbody >
<tr v-for="(ProductCart, index) in carrito" :key="index.id">
<td>{{ProductCart.name}}</td>
<td>{{ProductCart.cantidad}}</td>
<td>{{ProductCart.precio}}</td>
<td>{{ProductCart.cantidad * ProductCart.precio}}</td>
<td>
<form method="post">
<input :value="csrf" type="hidden" name="_token" >
<input type="hidden" name="id" id="id" value="" >
<button class="btn btn-danger" type="submit"> Remove</button>
</form>
</td>
</tr>
<tr>
<th colspan="2"></th>
<td>
<h5>Total</h5>
</td>
<td align="right">
<h5>{{ total }}</h5>
</td>
</tr>
</tbody>
scrip of component of the table
data(){
return{
csrf: document.head.querySelector('meta[name="csrf-token"]').content,
carrito: [],
}
},
created(){
EventBus.$on('agregado', data => {
this.carrito.push(data)
})
},
in my console I receive the error:
Error in event handler for "agregado": "TypeError: _this.carrito.push is not a function"
Related
I have 2 entities - Invoice and InvoiceProduct. Invoice class has a field List of InvoiceProduct because Invoice has #OneToMany mapping on InvoiceProduct.
I want to send the List of InvoiceProduct to Thymeleaf with with editable fields with a Submit button. When I click on Submit button, the new edited List should be returned to the controller. However, I am able to send the list to the view, but when I send the edited list to controller, it is being passed as 'null'.
update-invoice.html:
<form action="#" th:action="#{/api/invoice/saveInvoice}" th:object="${invoice}" method="POST">
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
<th>PID</th>
<th>Quantity</th>
<th>Unit Price</th>
</tr>
</thead>
<tbody>
<tr th:each="temp : ${invoice?.invoiceProducts}" >
<td><input name="invoiceProducts[${tempStat.index}].productId" th:value="${temp.productId}"/></td>
<td><input name="invoiceProducts[${tempStat.index}].quantity" th:value="${temp.quantity}"/></td>
<td><input name="invoiceProducts[${tempStat.index}].price" th:value="${temp.price}"/></td>
</tr>
</tbody>
</table>
<button type="submit" class="btn btn-info col-2">Submit</button>
</form>
InvoiceController:
#PostMapping("/saveInvoice")
public String postInvoice(#ModelAttribute("invoice") Invoice invoice) {
logger.info("invoice products " + invoice.getInvoiceProducts());
return "dummy";
}
What else do I need to add so that my update-invoice.html passes the list to my controller ?
You can try something like below as an example for thymleaf:-
<form method="post" th:action="#{/users/}" th:object="${userInfo}" class="col card p-3 mb-5">
<div class="form-group">
<label for="firstName">First Name</label>
<input id="firstName" placeholder="Enter First Name" required type="text" th:field="*{firstName}"
class="form-control"/>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input id="lastName" placeholder="Enter Last Name" required type="text" th:field="*{lastName}"
class="form-control"/>
</div>
<div class="form-group">
<label for="role">Role</label>
<select id="role" required th:field="*{role}" class="form-control ">
<option value="" hidden>Select a role</option>
<option th:each="role : ${T(com.springhow.examples.springboot.thymeleaf.domain.entities.Role).values()}"
th:value="${role}"
th:text="${role}">
</option>
</select>
</div>
<input type="submit" class="btn btn-primary" value="Create User">
</form>
and into Controller:-
#RequestMapping(value = "/", method = RequestMethod.POST)
public String createUser(Model model, #ModelAttribute UserInfo userInfo) {
UserInfo user = userService.createUser(userInfo);
return "redirect:/users/";
}
In Laravel-5.8 project, I am working on dynamic input form.
The main model is AppraisalGoal while the second model is AppraisalGoalDetail
Controller
public function create()
{
$goal = new AppraisalGoal();
$goaldetail = new AppraisalGoalDetail();
return view('appraisal.appraisal_goals.create')
->with('goal', $goal)
->with('goaldetail', $goaldetail) ;
}
public function store(StoreAppraisalGoalRequest $request)
{
DB::beginTransaction();
try {
$goal = new AppraisalGoal();
$goal->weighted_score = $request->weighted_score;
$goal->goal_title = $request->goal_title;
$goal->goal_description = $request->goal_description;
if ($request->appraisal_doc != "") {
$appraisal_doc = $request->file('appraisal_doc');
$new_name = rand() . '.' . $appraisal_doc->getClientOriginalExtension();
$appraisal_doc->move(public_path('storage/documents/appraisal_goal'), $new_name);
$goal->appraisal_doc = $new_name;
}
$goal->save();
foreach ( $request->activity as $key => $activity){
$startDate = Carbon::parse($request->start_date[$key]);
$endDate = Carbon::parse($request->end_date[$key]);
$insert_array = [
'kpi_description' => $request->kpi_description[$key],
'activity' => $request->activity[$key],
'start_date' => $startDate ->toDateTimeString(),
'end_date' => $endDate->toDateTimeString(),
];
AppraisalGoalDetail::create($insert_array );
}
DB::commit();
Session::flash('success', 'Goal is created successfully');
return redirect()->route(goals.index');
} catch (Exception $exception) {
DB::rollback();
Session::flash('error', 'Action failed! Please try again');
return redirect()->route('goals.index');
}
}
the create.blade view is shown below
<form action="{{route('goals.store')}}" method="post" class="form-horizontal" enctype="multipart/form-data">
{{csrf_field()}}
<div class="card-body">
<div class="form-body">
<div class="row">
<div class="col-12 col-sm-6">
<div class="form-group">
<label class="control-label"> Goal Title:<span style="color:red;">*</span></label>
<input type="text" name="goal_title" value="{{ old('goal_title', $goal->goal_title) }}" placeholder="Enter goal title here" class="form-control">
</div>
</div>
<div class="col-sm-12">
<div class="form-group">
<label>Goal Description</label>
<textarea rows="2" name="goal_description" class="form-control" value="{{old('goal_description',$goal->goal_description)}}" placeholder="Enter Goal Description here ...">{{old('goal_description',$goal->goal_description)}}</textarea>
</div>
</div>
<div class="col-sm-12">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Activity<span style="color:red;">*</span></th>
<th scope="col">KPI<span style="color:red;">*</span></th>
<th scope="col">Start Date<span style="color:red;">*</span></th>
<th scope="col">End Date<span style="color:red;">*</span></th>
<th scope="col"><a class="btn btn-info addRow"><i class="fa fa-plus"></i></a></th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="activity[]" class="form-control activity" ></td>
<td><input type="text" name="kpi_description[]" class="form-control kpi_description" ></td>
<td><input type="date" class="form-control start_date" placeholder="dd/mm/yyyy" name="start_date[]" min="{{Carbon\Carbon::now()->firstOfYear()->format('Y-m-d')}}" max="{{Carbon\Carbon::now()->lastOfYear()->format('Y-m-d')}}"></td>
<td><input type="date" class="form-control end_date" placeholder="dd/mm/yyyy" name="end_date[]" min="{{Carbon\Carbon::now()->firstOfYear()->format('Y-m-d')}}" max="{{Carbon\Carbon::now()->lastOfYear()->format('Y-m-d')}}"></td>
<td><a class="btn btn-danger remove"> <i class="fa fa-times"></i></a></td>
</tr>
</tbody>
</table>
</div>
<div class="col-12 col-sm-6">
<div class="form-group">
<label class="control-label"> Weight(%):<span style="color:red;">*</span></label>
<input type="number" name="weighted_score" placeholder="Enter weighted score here" class="form-control" max="120">
</div>
</div>
<div class="col-12 col-sm-6">
<div class="form-group">
<label class="control-label"> Attachment:</label>
<div class="custom-file">
<input value="{{old('appraisal_doc',$goal->appraisal_doc)}}" type="file" name="appraisal_doc" class="custom-file-input" id="customFile">
<label class="custom-file-label" for="exampleInputFile">Choose file</label>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- /.card-body -->
<div class="card-footer">
<button type="submit" class="btn btn-primary">{{ trans('global.save') }}</button>
</div>
</form>
AppraisalGoal is foreignkey to AppraisalGoalDetail. AppraisalGoalDetail is an Array.
The way the application operates is that, When the user clicks the submit button, the application saves into AppraisalGoal and pick its id and saves it with the other data into AppraisalGoalDetail.
However, the validation is giving issue. Whenever the user submits and the page is validated, all went blank upon showing the error page, meaning that I need to input them all over again.
I was able to resolve these ones that belong to AppraisalGoal model by using old() help function and it works:
<div class="col-12 col-sm-6">
<div class="form-group">
<label class="control-label"> Goal Title:<span style="color:red;">*</span></label>
<input type="text" name="goal_title" value="{{ old('goal_title', $goal->goal_title) }}" placeholder="Enter goal title here" class="form-control">
</div>
</div>
<div class="col-sm-12">
<div class="form-group">
<label>Goal Description</label>
<textarea rows="2" name="goal_description" class="form-control" value="{{old('goal_description',$goal->goal_description)}}" placeholder="Enter Goal Description here ...">{{old('goal_description',$goal->goal_description)}}</textarea>
</div>
</div>
I don't know how to resolve these ones that belong to AppraisalGoalDetail:
<tr>
<td><input type="text" name="activity[]" class="form-control activity" ></td>
<td><input type="text" name="kpi_description[]" class="form-control kpi_description" ></td>
<td><input type="date" class="form-control start_date" placeholder="dd/mm/yyyy" name="start_date[]" min="{{Carbon\Carbon::now()->firstOfYear()->format('Y-m-d')}}" max="{{Carbon\Carbon::now()->lastOfYear()->format('Y-m-d')}}"></td>
<td><input type="date" class="form-control end_date" placeholder="dd/mm/yyyy" name="end_date[]" min="{{Carbon\Carbon::now()->firstOfYear()->format('Y-m-d')}}" max="{{Carbon\Carbon::now()->lastOfYear()->format('Y-m-d')}}"></td>
<td><a class="btn btn-danger remove"> <i class="fa fa-times"></i></a></td>
</tr>
How do I get this corrected that the page should still retain the data after submit and validation error?
Thank you
When You get Validation Error & something fault in server..You redirect the page & withInput() function like this..
return redirect()->route('goals.index')->withInput(['goal_title' => $request->goal_title, 'goal_description' => $request->goal_description]);
It will sork & show your value which you give to update
Received http://examle.com/ajax/login.html:
<form method="post" action="/login.html" name="formLogin" data-ng-model="formLogin" data-ng-submit="submitLogin($event)" novalidate="novalidate" >
<input type="hidden" csrf="csrf" data-ng-model="formLogin.csrf" value="" name="LoginForm[csrf]">
<input type="text" data-ng-minlength="2" data-ng-required data-ng-model="formLogin.email" placeholder="e-mail" autofocus="autofocus" name="LoginForm[email]"></div>
<span class="error" ng-show="formLogin['LoginForm[email]'].$error.required">Required!</span>
<input type="text" data-ng-minlength="2" data-ng-required data-ng-model="formLogin.password" placeholder="password" autofocus="autofocus" name="LoginForm[password]"></div>
<span class="error" ng-show="formLogin['LoginForm[password]'].$error.required">Required!</span>
<button ng-disabled="formLogin.submitted" name="login-button" class="btn btn-primary" type="submit">OK</button>
</form>
The directive code looks as below:
app.directive('formLogin', function(){
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
var inputs = element[0].querySelectorAll('input');
}
};
});
In a classic example, if specify the name of the form, the form controller will be published into related scope, under this name. Is it possible to do for AJAX-loaded form, something like?
The problem is in the validation inputs after loading form.
How can I add validation for minimum length to a Textbox and display custom error messages?
I want validation for the following:
UserName to have a minimum length of 6
Password and Confirm Password to match
Address1 is required
Here is the code for the popup template. The specified minlength in the template is not working but the maxlength is working properly.
<script id="popup_editor" type="text/x-kendo-template">
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<label for="UserName"><b>UserName*</b></label>
</td>
<td>
<div class="control-row">
<input type="text"
name="UserName"
id="UserName"
class="k-input k-textbox"
required
**minLength**="6"
maxlength="8"
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter username"/>
<span class="k-invalid-msg" data-for="UserName" ></span>
</div>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<div>
<label for="Password"><b>Password*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="password"
id="Password"
name="Password"
class="k-input k-textbox"required
validationMessage="Please enter Password"/>
<span class="k-invalid-msg" data-for="Password"></span>
</div>
</td>
<td>
<div>
<label for="ConfirmPassword" style=""><b>Confirm Password</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="password"
id="ConfirmPassword"
name="ConfirmPassword"
class="k-input k-textbox"required
validationMessage="Please enter Confirm Password"/>
</div>
</td>
</tr>
<tr>
<td>
<div>
<label for="Company_Name"><b>Company Name*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input name="Company_Name"
id="Company_Name"
required
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter Valid CompanyName"/>
</div>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<div>
<label for="First_Name"><b>First Name*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="text"
name="First_Name"
id="First_Name"
data-type="string"
data-bind="value:First_Name"
class="k-input k-textbox" required
pattern="[a-zA-Z]+"
validationMessage="Please enter FirstName"/>
</div>
</td>
<td>
<div>
<label for="Last_Name"><b>Last Name*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<input type="text"
id="Last_Name"
name="Last_Name"
class="k-input k-textbox" required
pattern="[a-zA-Z]+"
validationMessage="Please enter LastName"/>
</div>
</td>
</tr>
<tr>
<td>
<div>
<label for="Address1"><b>Address1*</b></label>
</div>
</td>
<td>
<div class="k-edit-label">
<textArea style="resize: none;"
rows="5"
cols="18"
name="Address1"
maxlength="150"
id="Address1" required
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter Address">
</textarea>
</div>
</td>
</tr>
</table>
You can add custom validation for popup editing within the dataSource of your grid.
var dataSource = new kendo.data.DataSource({
transport: {
...
},
schema: {
model: {
id: "UserName",
fields: {
UserName: {}
Password: {}
ConfirmPassword: {}
Company_Name: {}
First_Name: {}
Last_Name: {}
Address1: {
validation: {
minLength: function (input) {
if (input.is("[name=UserName]")) {
return input.val().length >= 6;
}
return true;
},
match: function (input) {
if (input.is("[name=ConfirmPassword]")) {
return input.val() == $("#Password").val();
}
return true;
}
}
}
}
}
}
});
There are a few things to respect:
The validation runs for ALL input elements within your popup, therefore
you only have to define it for ONE of the fields in your model. Which one does not matter.
you have to check which input element is checked in the current run, which does the if statement in my example.
you have to append a return true at the end of each and every rule you define or otherwise you'll get an error message for every input you're not explicitly checking. If there's no return value passed, kendo automatically assumes the check had a false result.
Every validation rule needs its own validation message or otherwise your validation tooltip box will only display a warning logo without any text. You can add it as an html attribute (data-{validation rule}-msg) in your input elements, like this:
<input type="text"
name="UserName"
id="UserName"
class="k-input k-textbox"
required
maxlength="8"
pattern="[a-zA-Z0-9]+"
validationMessage="Please enter username"
data-minLenght-msg="Username must be at least 6 characters"/>
<input type="password"
id="ConfirmPassword"
name="ConfirmPassword"
class="k-input k-textbox"
required
validationMessage="Please enter Confirm Password"
data-match-msg="Password and confirmation must be equal"/>
Hope this helps
In rules add this:
match: function (input) {
if ((input.is('[name=\'Password\']') || input.is('[name=\'ConfirmPassword\']'))&& $('#ConfirmPassword').length !== 0) {
if ($('#Password').val().length > 0 && $('#ConfirmPassword').val().length > 0) {
if (input.is('[name=\'Password\']')) {
return input.val() === $('#ConfirmPassword').val();
}
else if (input.is('[name=\'ConfirmPassword\']')) {
return input.val() === $('#Password').val();
}
}
}
return true;
},
minLength: function (input) {
if (input.is("[name=UserName]")) {
return input.val().length >= 6;
}
return true;
},
requiredAddress: function (input) {
if (input.is("[name=Address1]")) {
return $('#Address1').val() !== '' ? false : true;
}
return true;
}
Having a hard time figuring out how to add an increment value for each id attribute within the div contents with cloned jQuery object.
http://jsfiddle.net/hvK8d/
===================== HTML=====================
<div class="upload-file-container">
<div class="uploadFile left clearfix">
<input type="file" id="FileUpload1">
<table id="RadioButtonList1">
<tbody>
<tr>
<td><input type="radio" value="Resume" id="RadioButtonList1_1">
<label for="RadioButtonList1_1">Resume</label></td>
<td><input type="radio" value="Letter of Recommendation" id="RadioButtonList1_2">
<label for="RadioButtonList1_2">Letter of Recommendation</label></td>
<td><input type="radio" value="Other" id="RadioButtonList1_3">
<label for="RadioButtonList1_3">Other</label></td>
</tr>
</tbody>
</table>
</div>
Remove </div>
<div class=""><a class="plus" href="javascript:;">plus one</a></div>
===================== JQUERY =====================
//Cloning upload file control
$('.remove').live('click', function () {
if (confirm("Are you sure you wish to remove this item?")) {
$(this).parent().slideUp('fast', function () {
$(this).remove();
});
}
return false;
});
$('.plus').click(function () {
console.log('cloning');
var divCloned = $('.upload-file-container:first').clone();
divCloned.hide().insertAfter('.upload-file-container:last').slideDown('fast');
return false;
});
For the sake of completeness I will put here a small solution making use of a "template."
A class for hiding the template:
.upload-file-container.template {
display: none;
}
A small function to do replacements:
$.fn.template = function(variables) {
return this.each(function() {
this.innerHTML = this.innerHTML.replace(/{{(.+)}}/g, function(match, variable) {
return variables[variable];
});
return this;
});
};
A template:
<div class="upload-file-container template">
<div class="uploadFile left clearfix">
<input type="file" id="FileUpload{{id}}">
<table id="RadioButtonList{{id}}"><tbody>
<tr>
<td>
<input type="radio" value="Resume" id="RadioButtonList{{id}}_1">
<label for="RadioButtonList{{id}}_1">Resume</label>
</td>
</tr>
</tbody></table>
</div>
</div>
Usage:
var count = 0;
var divCloned = $(".upload-file-container.template")
.clone()
.removeClass("template")
.template({
id: count++
});
Instead of using numbered IDs, you should be using the array-like notation (e.g. RadioButtonList[]) in the name attribute, and wrap your labels around the inputs:
<td>
<label for="RadioButtonList1_1">
<input type="radio" value="Resume" name="RadioButtonList1[]">
Resume
</label>
</td>
<td>
<label for="RadioButtonList1_2">
<input type="radio" value="Letter of Recommendation" name="RadioButtonList2[]">
Letter of Recommendation
</label>
</td>
<td>
<label for="RadioButtonList1_3">
<input type="radio" value="Other" name="RadioButtonList3[]">
Other
</label>
</td>
P.S. You should also consider using a more descriptive name than RadioButtonList.