VueJs 2 way data binding changes lost - javascript

I have a list of products:
For each product they can select a time type (per hour, per day etc).
When they have done so and clicked book, it adds the product to cart;
this is done inside addToCart below on the line that is bolded.
addToCart: function (resultId, cartId) {
var that = this;
this.shoppingCart.forEach(function (cartItem, cartIndex) {
cartItem.added = false;
if (cartIndex == cartId)
{
cartItem.added = true;
that.results.forEach(function (resultItem, resultIndex) {
if (resultItem.id == resultId) {
that.shoppingCart.$set(cartIndex,
{
productTimeType: cartItem.productTimeType,
quantity : cartItem.quantity
});
var numberOfBookings = (parseInt(resultItem.numberBookings, 10) + cartItem.quantity);
that.results.$set(resultIndex, {
numberBookings: numberOfBookings,
name: resultItem.name,
quantity: resultItem.quantity,
id: resultItem.id,
category_id: resultItem.category_id,
description: resultItem.description,
image: resultItem.image,
created_at: resultItem.created_at,
updated_at: resultItem.updated_at
});
The html:
<tr v-for="result in results">
<td>
<form class="form-inline" #submit.prevent='addToCart(result.id, $index)'>
<input v-model="shoppingCart[$index].quantity" class="form-control" placeholder="Quantity" name="quantity" type="text">
<select v-model="shoppingCart[$index].productTimeType" class="form-control input-lg"><option value="" selected="selected">All types</option><option value="1">Whole day</option><option value="2">Half day</option><option value="3">Per hour</option></select>
<input class="btn btn-warning" type="submit" value="add to cart">
</form>
When I debug this, and console.log the values it's doing it perfectly. Then it seems like there's some sort of refresh happening, and all the fields are reset on the page to what they were before, and no values are updated.

Change the type of your input to button instead of submit
<input class="btn btn-warning" type="button" value="add to cart">

Ok,in my case the issue was with the fact that I was outputting the select box with Laravel using Laravel Collective's package, and each time it did so, it generated the markup with a certain option selected. This was resetting the dropdown.
It would seem that there are better ways to work with VueJs and the backend like fetching the data or the html from the server and passing that to VueJs to generate the dropdown (if the dropdown is dynamic). I will follow an approach similar to this.

Related

Issue using Angular, Local Storage and NgIf

I'm currently building an application that is making use of information stored in local storage as the user works their way through the application.
When they get to one particular question, they'll be shown different text and options depending on the choice they select. If they select "one" applicant, then on a following step they will be shown a single input field. If they select "two" applicants they'll be shown two input fields.
I've been able to get this to a certain extent, it's just that it doesn't work exactly how I expect it to. It will only use the value in local storage after the application is reloaded, not during the current session.
Here's a rough example. If I've never used the application before and there is nothing in my local storage and I select "two" applicants:
Screenshot One
On the subsequent step, it only shows me one field (this is default, but there should be two because that's what I selected) and it hasn't populated the text text:
Screenshot Two
Now, if I reload the application and go back to the same question and select "one" this time:
Screenshot Three
This time around, it will show the text associated with two users and the two input fields, even though I selected "one":
Screenshot Four
So it appears to have a "delay" (for want of a better word) where it will only show the choice made on the last session.
I've tried a few variants of how to tackle this, but they all seem to give me the same result, and I've already looked around Stackoverflow and Google to see if anyone has a similar problem but I haven't be able to find anything that helps me.
Here's the relevant code from my component.html:
<mat-step label="Step 2" [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup">
<div ng-controller="step2">
<h2>How many people are applying?</h2>
<mat-button-toggle-group>
<div *ngFor="let step2option of step2options">
<mat-button-toggle (click)="getStep2Val(Oname);" class="btn btn-primary step-button" id="{{step2option.id}}" [ngClass]="status ? 'selected' : ''"><span #Oname>{{step2option.text}}</span></mat-button-toggle>
</div>
</mat-button-toggle-group>
<div>You chose <strong>{{ selectedStep2option }}!</strong></div>
<button mat-stroked-button (click)="goToNext()" class="btn btn-secondary continue-btn" [disabled]="selectedStep2option === 'none'">Continue</button>
</div>
</form>
</mat-step>
<mat-step label="Step 3" [stepControl]="thirdFormGroup">
<form [formGroup]="thirdFormGroup">
<div ng-controller="step3">
<h2>What <span *ngIf="users === 'One'">{{text1app}}</span> <span *ngIf="users === 'Two'">{{text2app}}</span>?</h2>
<div class="input-group" *ngIf="users == 'One' || 'Two'" >
<p>Applicant 1</p>
<span class="input-group-addon">£</span>
<input type="number" (change)="getStep3Val()" (keyup)="getStep3Val()" [(ngModel)]="app1income" [ngModelOptions]="{standalone: true}" id="step3appVal" min="0" step="500" data-number-to-fixed="2" data-number-stepfactor="500" />
{{app1income}}
</div>
<div class="input-group" *ngIf="users == 'Two'">
<p>Applicant 2</p>
<span class="input-group-addon">£</span>
<input type="number" (change)="getStep4Val()" (keyup)="getStep4Val()" [(ngModel)]="app2income" [ngModelOptions]="{standalone: true}" id="step4appVal" min="0" step="500" data-number-to-fixed="2" data-number-stepfactor="500" />
{{app2income}}
</div>
<button mat-stroked-button (click)="goToNext()" class="btn btn-secondary continue-btn" [disabled]="app1income === 0">Continue</button>
</div>
</form>
</mat-step>
And from my component.ts:
users: string;
getUsers() {
this.users = this.readLocalStorageValue('Number of applicants');
}
readLocalStorageValue(key: string): string {
return localStorage.getItem(key);
}
selectedStep2option: string = 'none';
step2options = [
{
text: 'One',
id: 'step2one'
},
{
text: 'Two',
id: 'step2two'
}
];
getStep2Val (Oname: any) {
this.selectedStep2option = Oname.textContent;
localStorage.setItem('Number of applicants', Oname.textContent);
}
text1app: string = 'is your income';
text2app: string = 'are your incomes';
At the moment I can't seem to figure out why there is this delay in the choice the user makes. Does anyone have any idea as to why this might be doing this? Or is this a completely long-winded way to go about it and I'm missing an much easier way of having this conditional logic. I'm pretty new to Angular so I could be going down the completely wrong track here.
Any help would be greatly appreciated.
Never mind. I figured it out. It was a simple case of having my getUsers() function call in the wrong place.
It should've been here:
<button mat-stroked-button (click)="goToNext(); getUsers()" class="btn btn-secondary continue-btn" [disabled]="selectedStep2option === 'none'">Continue</button>
Instead it was on an earlier step.
Typical case of once you ask someone for help, the solution jumps in your face.

how to apply validation to dynamically added field to form

I have form with two fields and until those fields are filled with some text my submit button will be disabled but now if i add third field dynamically angular JS will not support validation for the third field which is added dynamically.
link https://jsfiddle.net/vikrantkki/zzhgaguz/57/
<button ng-click="adddynamicfield()">add dynamic field<button>
<form name="dynamicform" novalidate="true">
<input type ="text" dynamic-name name="name" ng-model="dynamicform1.name" required>
<input type ="text" dynamic-name name="age" class="age" ng-model="dynamicform1.age" required >
<button type="submit" ng-disabled="dynamicform.$invalid">submit</button>
</form>
The problem is you are not compiling the newly added html. You can research on $compile and it should solve the issue.
But what I recommend for your case is to use an array to represent the dynamic fields, so you can get the model values more easily.
fiddle
$scope.dynamicFields = [];
$scope.adddynamicfield = function() {
var index = $scope.dynamicFields.length;
$scope.dynamicFields.push({
name: 'field' + index,
model: '',
className: 'field',
});
}

Get element by name using knockout

I am creating input elements like below:
<input type="text" class="form-control" data-bind="value: attr: { name: Data[' + $index() + ']'}" />
I have another button which creates multiple inputs of above with its click.
And I also have my main button click as:
<input type="button" value="Check Data" class="btn btn-primary" data-bind='click: verify.bind($data, event)' />
In my knockout I have:
self.verify= function (data, event) {
//here I want the data that is entered in each of the inputs.
}
On the above button click I want to get the value of all the inputs. In JS I could have done elements by name and it would give me that element. But how can I get that to work here.
Updated code:
I have this in my HTML:
<div data-bind="foreach: { data: myData }">
<div class="form">
<div class="myClass">
<input type="text" class="form-control" data-bind="value: $data.textbox, attr: { name: 'MyData[' + $index() + '].Textbox'}" />
</div>
<div class="myClass">
<input type="button" value="Add More" class="btn btn-primary" data-bind="click: $parent.add"/>
</div>
</div>
</div>
When the user clicks Add More, it adds on more it adds one more text box.
Then at last I have a button as:
<div class="form">
<input type="button" value="Check Data" class="btn btn-primary" data-bind='click: checkData' />
</div>
When the user clicks on Check Data button I just need to some validation on the all the data entered in the textbox. The validation needs to be done on client side.
In my knockout I have:
this.add = ko.observableArray();
this.add = function () {
self.myData.push(
{
textbox: ""
});
};
this.checkData = function (){
//Here I want to get whats entered in all the textboxes
}
It's exceedingly likely that your entire approach is wrong.
Your HTML input elements don't need names.
Your viewmodel methods do not need to know anything about the HTML elements that display their values.
You do not need to bind your event handlers with special parameters.
The view (the HTML page) is used as a tool for modifying the viewmodel. All data you need for verification is in the viewmodel, given that you have made everything that the user can change an observable.
function Test() {
var self = this;
self.users = ko.observableArray([
{ name: ko.observable("John Doe") },
{ name: ko.observable("Jane Doe") }
]);
self.verify = function () {
var usernames = self.users().map(function (u) { return ko.unwrap(u.name) });
alert('You have entered these users\n\n' + usernames.join('\n'));
};
}
var vm = new Test();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="foreach: users">
<input type="text" class="form-control" data-bind="value: name" /><br>
</div>
<button class="btn btn-primary" data-bind='click: verify'>Check Data</button>

how to add multiple search data

so I need help with my code. My boss wanted to search in my dropdown category multiple times for example in ID, more likely a range value, example i want to search SCP ID values: 123 and 169, all significant data will show that matches the record.i attach my UI sample belowsample UI my problem is that in my UI i can only search 1 value only for the same category. someone help me pls with the function and design. thanks alot.
This is my HTML:
<input type="text" id="txtsid" style="width: 70%; margin-left:2px;" value="" ng-model="sid" class="input-group inline form-control" placeholder="SCP ID" ng-required="true" required>
<button id="scpid1" class="btn btn-primary" onclick="addFields()">ADD</button>
This is my function:
$scope.sid=$scope.sidData;
$scope.filterSearch2nd = function(sid) {
if(sid ==""){
sid="scpid";
}
$rootScope.loader = true;
skinCareProdService.filter2ndSearch(sid)
.then(function(data){
$scope.rawSCP = data.data;
$rootScope.loader = false;
$scope.sidData=data.data[0].SCP_id;
}
);
}
i also use append

jQuery .val('xxx') not setting value, but .attr('value', 'xxx') is?

I have a table which is populated with javascript, fetching data via ajax. I have a <tr> template which I clone and set the values within to the data retrieved via the ajax request. I'm using Twitter bootstrap's popovers, so that users can click on a cell, which pops the popover with an input/select etc prompting the user to change the cell value. The problem occurs when I am setting the value of those inputs. When I am building each row, I set the value of the input in the popover template with .val('xxx'), but when I log it/click the cell and view the popover, nothing is changed; conversely, if I set it with .attr('value', 'xxx'), it works just fine.. why would .val('xxx') not work?
Here's what the meat of it looks like..
Row template:
....
<td>
<div class="last-name popover-toggle">
<span class="vlabel">----</span>
<div class="popout">
<input type="text" name="last_name" value=""/>
<div class="popout-button-container">
<button type="button" class="btn btn-primary btn-small cancel-field">Cancel</button>
<button data-url="{{ url('edit_lead.json') }}" type="button" class="btn btn-primary btn-small save-field">Save</button>
</div>
</div>
</div>
</td>
....
Setting input value:
...
if (data['last_name']) {
$nRow.find('.last-name input[name=last_name]').val(data['last_name']);//.attr('value', data['last_name']);
$nRow.find('.last-name .vlabel').text(data['last_name']);
}
registerPopover($nRow.find('.last-name'), 'Last Name');
....
Register popover:
function registerPopover(el, title) {
var options = {
animation: false,
content: el.find('.popout').html(),
html: true,
trigger: 'manual'
};
if (typeof(title) != 'undefined') {
options['title'] = title;
}
el.popover(options);
}
Not sure what is your actual problem, question is not very obvious to me but there is a difference between attr and val. The attr method sets/change the attribute of an input/element in the source and you may see it using browser's inspection tool, on the other hand, val method sets/update the rendered property which is in the memory but it doesn't effect the original source/HTML in the browser's source code. For example, if you do something like this
HTML:
<input type = "text" name="txt" id = "txt" value = "Hello!" />
JS:
$('#txt').val('World!').clone().insertAfter($('#txt'));
And check the source code, then you'll see there is two input elements and both have value attribute Hello! but on the screen both have world!. Check this detailed answer.

Categories