Retaining response data in multiple checkboxes (Vue.js) - html

Iam new to vue. So iam trying to experiment requests and response through web servers. I have mutiple checkboxes as shown:
<li>
<div class="config-label">Photoshop IRB</div>
<div class="config-value">
<input
type="checkbox"
class="rounded text-light mr-3 bigger-checkboxes"
value="photoshop"
v-model="checkedCategories"
/>
</div>
</li>
<li>
<div class="config-label">Flashpix</div>
<div class="config-value">
<input
type="checkbox"
class="rounded text-light mr-3 bigger-checkboxes"
value="flashpix"
v-model="checkedCategories"
/>
</div>
</li>
Multiple checkboxes this way. The script is:
export default{
data(){
return {
checkedCategories : []
};
},
created() {
this.getExtractionConfig().then((data) => {
this.checkedCategories = data;
});
},
Now how do i retain the values of the checkboxes from the response ?

Ohkay, after debugging i found the solution for the silly lapse on my side. I had to select the key in data. So it was :
created() {
this.getExtractionConfig().then((data) => {
this.checkedCategories = data.selected_categories;
});

Related

How do I calculate income and expense in an expense tracker JavaScript

I'm trying to add the value of a checked radio button in an object in another function.
However there is nothing being added and no error returned.
I'm building an expense tracker and adding those value (either income or expense) is important in my calculation.
Nb: when I try to console.log in the function where i capture the checked value, it works perfectly but when i try to add that value to the array object in another function nothing is added.
const TransactionType = document.getElementsByName('selector');
addbtn.addEventListener('click', function() {
if (expense.value == '' || amount.value == '' || date.value == '') {
alert('Please fill all the fields!!!');
return;
} else {
const userExpense = {
id: generateID(),
type: getTransactionType(), // here is the problem nothing is added
date: date.value,
expense: expense.value,
amount: amount.value
};
userInput.push(userExpense);
localStorage.setItem('data', JSON.stringify(userInput));
location.reload();
}
});
function getTransactionType() {
TransactionType.forEach(item => {
if (item.checked) {
return item.value;
}
});
}
<!-- radio buttons to choose the type of transaction -->
<div class="container">
<h3>Select the type of transaction:</h3>
<ul>
<li>
<input type="radio" id="type-income" name="selector" value="income">
<label for="type-income">Income</label>
</li>
<li>
<input type="radio" id="type-expense" name="selector" value="expense">
<label for="type-expense">Expense</label>
</li>
<!-- <button onclick=" getTransactionType()">see value</button> -->
</ul>
</div>
The code is incomplete. There is no addbtn and no handling of displaying the localStorage
Why do you reload?
TransactionType.forEach(item => {
if (item.checked) {
return item.value;
}
});
does nothing.
The return statement is not interesting in a forEach.
Here is a simpler method: I use delegation.
There is no need to test that anything is checked because you use radios. It needs more code if you were using a checkbox.
const getTransactionType = () => document.querySelectorAll('[name=selector]:checked')[0].value;
document.querySelector('.container').addEventListener('click', () => {
console.log(getTransactionType())
})
<!-- radio buttons to choose the type of transaction -->
<div class="container">
<h3>Select the type of transaction:</h3>
<ul>
<li>
<input type="radio" id="type-income" name="selector" value="income">
<label for="type-income">Income</label>
</li>
<li>
<input type="radio" id="type-expense" name="selector" value="expense">
<label for="type-expense">Expense</label>
</li>
</ul>
</div>

React map is duplicating DOM Elements

I have the following issue:
I am building a web application, BackEnd in spring and FrontEnd in React.
Now I am adding a feature that shows how many products are in the cart while the client is clicking on "buy". The problem is that when I do a map to get the API in the dom tree, it seems like is duplicating the element.
Images:
Bug: "Carrinho ( )" is being duplicated
Note:
I am consuming two APIs
Code:
import React, { useEffect, useState } from 'react';
import {
Row,
CardBody,
Container,
} from 'reactstrap';
import api from '../../resources/api_produtos';
import apiCart from '../../resources/api_cart';
import axios from 'axios';
const Main = () =>{
const[product, setProduct] = useState([]);
const[cart, setCart] = useState([]);
const fetchData = () =>{
const productApi = api.get('');
const cartApi = apiCart.get('');
axios.all([productApi, cartApi]).then(
axios.spread((...allData) =>{
const allProductData = allData[0].data;
const allDataCart = allData[1].data;
setProduct(allProductData);
setCart(allDataCart);
console.log(allDataCart);
})
)
}
useEffect(() =>{
fetchData()
}, [])
return (
<div>
<div className="p-3 mb-2 bg-dark text-white d-flex justify-content-between">
<div>
<strong>Game Store</strong>
</div>
<div>
{cart.map(carrinho =>(
<div key={carrinho.id}>
<div>
Carrinho ( {carrinho.amount} ) HERE IS BEING DUPLICATED
</div>
</div>
))}
</div>
</div>
<Container>
<div className="jumbotron mt-3"><h1>Produtos</h1></div>
{product.map(produto => (
<div className="card mb-3">
<div key={produto.id}className="card-header d-flex justify-content-between">
<span>
Id: {produto.id}
</span>
<div>
<nav>
<form method="POST" action={"http://localhost:8080/comprar/" + produto.id}>
<input type="submit" className="btn btn-secondary" value="Comprar" ></input>
</form>
</nav>
</div>
</div>
<CardBody>
<Row>
<div className="col-12 col-sm-8 mb-3">
<div className="row">
<div key={produto.id}>
<div >
Nome: {produto.name}
</div>
<div >
Preço: R$ {produto.price}
</div>
</div>
</div>
</div>
<div className="col-12 col-md-4">
<figure key={produto.id}>
<img className="img-thumbnail"src={produto.image} />
</figure>
</div>
</Row>
</CardBody>
</div>
))}
</Container>
</div>
);
}
export default Main;
And this is how the API "Cart" looks like:
[{"amount":"7"},[{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"}]]
How do I fix this duplication?
The problem is the response object from your cart API.
It's bad-formed, since your BE is returning an array which gives no sense since the response includes one single cart.
So, the map function iterate over an array, modifying its content by the callback, place them in a new array, and then returns it.
So essentially you are trying to modify the obj on the index 0, which is and obj with the "amount" field, and then, you are trying to map an array at index 1.
So you have to update your response from the BE, something like that:
{
"id": "cart_id",
"items": []
}
Which has more sense compared with yours. Note that since items is an array you don't need the "amount" field, you can access it with carrinho.items.length for instance. Then render it with
<div key={carrinho.id}>
<div>Carrinho ({carrinho.items.length})</div>
</div>

Vue, changing the name of an input via list item click

I have an input that I'm using in relation two an unordered list with two list items, which is in place, but I"m trying to figure out how I can change the input name/id with the click of one of the list items.
The items are not links or buttons, so I just want to be able to click the item text and if 'Public' is clicked, the input name would become public, if 'Internal' is clicked I would want the input name to be internal
I'm using Vue which may have some better options, but basically I just want to send the name of the input later on in an ajax call and I only want the name to be determined by the click of a list item potentially with a default.
What is the best way to achieve this with Vue being used?
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li>Public</li>
<li>Internal</li>
</ul>
</div>
<div>
<input type="text" name="public">
</div>
</div>
</div>
First step: use component data to your advantage
You can simply store the desired input name attribute in the component data, e.g. inputName. Then, use v-on to bind a click event listener to your elements, so that whenever they are clicked, you invoke a method that updates the inputData property of your component.
new Vue({
el: '#app',
data: {
inputName: '',
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li v-on:click="setInputName('public')">Public</li>
<li v-on:click="setInputName('internal')">Internal</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Better: Use v-for to generate list items dynamically
If you don't want the manually provide the argument to the method, there's an easier way: you simply create a list of allowed names in the component data, too, and use v-for to generate the list dynamically:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: ['Public', 'Internal']
},
methods: {
setInputName(str) {
this.inputName = str.toLowerCase();
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName)">
{{ allowedName }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Even better: if there is no one-to-one correspondance between list item text and the desired name attribute
This can be useful in the case when, for example, you want the text to read Public but the name attribute to be another value. Instead of an array of strings, you can use an array of objects:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: [{
label: 'Public (or any other arbitrary text you like)',
name: 'public'
}, {
label: 'Internal (or any other arbitrary text you like)',
name: 'internal',
}]
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName.name)">
{{ allowedName.label }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>

File input with ng-model in nested components throws InvalidStateError

I have a ngform which includes a separate component to upload files. When I try to input a file in this component, the browser throws this error:
I don't understand where this might come from, here is my parent html:
<form
novalidate
#logosForm="ngForm"
(ngSubmit)="brandingService.setLogos(logosForm.value)">
<div class="columns">
<div class="column">
<app-file-upload
title="Logo principal"
name="logo"
label="Logo.png">
</app-file-upload>
</div>
</div>
Here is my child nested html (app-file-upload):
<div class="upload">
<span class="upload__label" [translate]="title"></span>
<div class="file is-fullwidth">
<label class="file-label">
<input
class="file-input"
type="file"
accept=".png, .jpg, .ico"
[name]="name"
(change)='handleFileInput($event)'
[(ngModel)]="file">
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
</span>
<span class="file-name">
{{label}}
</span>
</label>
</div>
<figure *ngIf="file" class="image previsualisation" [ngClass]="{'is-128x128': name == 'logo', 'is-48x48': name == 'favicon'}">
<img [src]="file">
</figure>
</div>
And here's the child's ts:
export class FileUploadComponent {
file: string | ArrayBuffer;
#Input()
title: string;
#Input()
name: string;
#Input()
label: string;
constructor() { }
handleFileInput(event: Event): void {
const userFile: File = (<HTMLInputElement> event.target).files[0];
if (userFile) {
this.label = userFile.name;
const reader: FileReader = new FileReader();
reader.onload = ((e: Event): void => {
const filereader: FileReader = <FileReader> e.target;
this.file = filereader.result;
});
reader.readAsDataURL((<HTMLInputElement> event.target).files[0]);
}
}
}
As I understand the error this might come from the fact that I try to bind on a file object (or string | ArrayBuffer) and so I try to change the value of this object and that is forbidden. I don't see how I could use the ngModel differently to get the child component to output the file uploaded by the user. If you have an idea, please help me, thanks !
While I don't immediately see an error in your code, file input fields in combination with NgModel show some very strange behaviours.
Ben Nadel recently wrote an article about how to properly access the file inputs value attribute using a ControlValueAccessor, perhaps you can adopt his method instead.
I suggest you to follow this link. use this way to upload a file by avoid duplicate files, maximum size.
/* Add application styles & imports to this file! */
#import url('https://unpkg.com/bootstrap#3.3.7/dist/css/bootstrap.min.css')
<div>
<label class="btn btn-primary">
Upload Documents <input type="file" #fileUpload (change)="fileChangeEvent($event)" onclick="this.value=null" multiple hidden style="display:none;">
</label>
</div>
<ul>
<li *ngFor="let fileName of selectedFileNames">{{fileName}} <button (click)="removeFile (fileName)" style="cursor: pointer;"><i class="fa fa-times"></i></button>
</li>
</ul>
//Typescript Code:
For Typescript code refer to
Working Demo

ng-model taking for all inputs after clicking edit

I am using AngularJS. I am generating pipeline-like structure. At first onload I am having one default ng-repeat value. After clicking "add more" I am displaying another list. It goes on adding as long as I am clicking the "add" button.
Here is my HTML:
Add button
<button data-ng-click="addNew()">Add New Workboard</button>
New pipeline will be created with Pipeline Names and one text box to add stageNames
<div data-ng-show="listOfLists.length > 0">
<div data-ng-repeat="list in listOfLists">
<div data-ng-repeat="pipeline in workboardstages track by $index">
<div class="added-eachboard">
<div class="form-group">
<input name="pipelineName" id="pipelineName" data-ng-
model="pipeline.pipelineName" type="text">
</div>
<ul class="simpleDemo workboard-drags" data-ng-repeat="(key,
workboardlist) in pipeline.workBoardStageMap">
<li data-ng-if="pipeline.pipelineName == key" ng-repeat="workboard in
workboardlist">{{workboard.stageName}}
<a href ="javascript:void(0)" data-ng-
click="editWorkboardStage(workboard.stageId)"><img src =
"resources/zingy/images/Edit-Small.png" class="TableIcon"></a>
</li>
</ul>
<div>
<p class="weak">Stage Name:</p>
<div class="form-group">
<input name="stageName" id="stageName" data-ng-
model="newworkboard.stageName" type="text">
</div>
</div>
</div>
</div>
</div>
</div>
Controller.js
$scope.listOfLists = [];
$scope.workboardStagesWithDefault = [
{
Name:"Test"
},
{
Name:"Test2"
},
{
Name:"Test3"
}
];
$scope.addNew = function(){
var clonedList = angular.copy($scope.workboardStagesWithDefault);
$scope.listOfLists.push(clonedList);
};
$scope.editWorkboardStage = function(stageId){
AccountService.editWorkboardStage(stageId).then(function(response){
$scope.newworkboard = response.data;
});
}
$scope.getAllWorkboardStages = function(){
AccountService.getAllWorkboardStages().then(function(response){
$scope.workboardstages = response.data;
$scope.listOfLists.push($scope.workboardstages);
});
}
After clicking edit i am displaying stage name in that particular text box.But the problem is it is displaying same for neighbouring pipeline also.I want to display only for that current pipeline.As i am displaying using ng-model it is taking for all pipelines.How to display the value only for that particular pipeline?
So, the problem is related to indexing. I made $scope.newworkboard index wise.
This is the solution: (newworkboard is based on pipeline index and pass index from editWorkboardStage function.)
<input name="stageName" id="stageName" data-ng-model="newworkboard[$index].stageName" type="text">
AND
<a href ="javascript:void(0)" data-ng-click="editWorkboardStage(workboard.stageId, $parent.$parent.$index)"><img src =
"resources/zingy/images/Edit-Small.png" class="TableIcon"></a>
HTML
<div data-ng-show="listOfLists.length > 0">
<div data-ng-repeat="list in listOfLists">
<div data-ng-repeat="pipeline in workboardstages track by $index">
<div class="added-eachboard">
<div class="form-group">
<input name="pipelineName" id="pipelineName" data-ng-
model="pipeline.pipelineName" type="text">
</div>
<ul class="simpleDemo workboard-drags" data-ng-repeat="(key,
workboardlist) in pipeline.workBoardStageMap">
<li data-ng-if="pipeline.pipelineName == key" ng-repeat="workboard in
workboardlist">{{workboard.stageName}}
<a href ="javascript:void(0)" data-ng-
click="editWorkboardStage(workboard.stageId, $parent.$parent.$index)"><img src =
"resources/zingy/images/Edit-Small.png" class="TableIcon"></a>
</li>
</ul>
<div>
<p class="weak">Stage Name:</p>
<div class="form-group">
<input name="stageName" id="stageName" data-ng-
model="newworkboard[$index].stageName" type="text">
</div>
</div>
</div>
</div>
</div>
</div>
Controller
In the controller make an array of newworkboard and assign response.data index wise.
$scope.newworkboard = [];
$scope.editWorkboardStage = function(stageId, index){
AccountService.editWorkboardStage(stageId).then(function(response){
$scope.newworkboard[index] = response.data;
});