Button that adds a new row when clicked in Vue 3 - javascript

First I must say that I'm a complete newbie in coding and Vue it's the first framework I'm learning and I'm terrible working with arrays at the moment. In the practice I am doing I am displaying the first five elements of the array in a table (I've filtered them in a new variable to do the v-for).
Now I need to add a button that when clicked will show me a new row of the original array, but I'm a bit stuck on how to do it. As u may see in the code below, contactList is the variable that has all the data, but I have no clue how to link it to the filtered one to show more data when clicked.
<template>
<h1 class="display-1 text-primary">Contacts</h1>
<button type="button" class="btn btn-outline-primary btn-lg" #click="addRandom">Add random</button>
<div class="container container__pos">
<table class="table table-hover">
<thead>
<tr>
<th class="col col__style">Picture</th>
<th class="col col__style">Name</th>
<th class="col col__style">Popularity</th>
<th class="col col__style">Won an Oscar</th>
<th class="col col__style">Won an Emmy</th>
</tr>
</thead>
<tbody>
<tr v-for="(element, index) of contactListed" :key="index">
<td scope="row">
<img
:src="element.pictureUrl"
:alt="element.name + ` image`"
class="image"
/>
</td>
<td> {{ element.name }}</td>
<td>{{ element.popularity }}</td>
<td>{{ wonAward(element.wonOscar) }}</td>
<td>{{ wonAward(element.wonEmmy) }}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import contacts from "./contacts.json";
export default {
data() {
return {
contactList: contacts,
contactListed: contacts.slice(0, 5),
};
},
methods: {
wonAward(element) {
if (element === true || element === true){
return "winner";
} else {
return "";
}
},
},
};
</script>

You can use a computed variable that holds the first N elements of the array, and have your button increment the value of N, like this:
<script>
import contacts from "./contacts.json";
export default {
data() {
return {
contactList: contacts,
nItems: 5
};
},
computed: {
contactListed() {
return this.contacts.slice(0, this.nItems)
}
},
methods: {
addRow() {
this.nItems++;
},
wonAward(element) {
if (element === true || element === true){
return "winner";
} else {
return "";
}
},
},
};
</script>
<template>
...
<button #click="addRow()" />
</template>

Related

Uncaught ReferenceError: firstSelectAll is not defined

I have this table with checkboxes. I use computed property in <th> v-model to check all the checkboxes in <td>
The problem is with my development it is working perfectly, but in deployment/build, it shows the error below when I click the checkbox responsible for checking all the checkboxes.
this is my table:
<table id="table">
<tr>
<th style="text-align: center">
<input
type="checkbox"
name="tableCheckBox"
v-model="firstSelectAll"
/>
</th>
<th style="text-align: right">#</th>
<th>Name</th>
<th>Program</th>
<th>Iteration</th>
<th>Stream</th>
<th>Group</th>
</tr>
<tr
v-for="(data, index) in firstFetchUserData"
:key="data.ind_id"
:value="data.ind_id"
style="cursor: pointer"
>
<td class="td-checkbox">
<input
type="checkbox"
v-model="selected"
:value="data"
number
/>
</td>
<td>{{ data.program_name }}</td>
<td>{{ data.iteration_name }}</td>
<td>{{ data.stream_name }}</td>
<td>{{ data.group_name }}</td>
</tr>
</table>
and this is my computed property that manages to check all of the checkboxes in <td>
data: () => ({
selected: [],
firstFetchUserData: []
}),
computed:{
firstSelectAll: {
get: function () {
return this.firstFetchUserData
? this.selected.length == this.firstFetchUserData.length
: false;
},
set: function (value) {
var selected = [];
if (value) {
this.firstFetchUserData.forEach(function (user) {
selected.push(user);
});
}
this.selected = selected;
},
},
}
here you can see in this link Check all checkboxes vuejs, I reference my code to the highest upvote in answers.

Get value from array data in Vue

I'm kinda new to Vue and i'm struggling to get one value from an array. I'm making an axios get request where I return an array of users containing the values (name, display_name, role, and few others fields). I'm able to get all these values and mount my table with the component below:
<template>
<div class="container">
<table class="mt-3 table roboto table-stripped table-hover table-sm">
<thead class="thead-light">
<th>Name</th>
<th>Username</th>
<th>Profile</th>
<th class="text-center">Is manager</th>
</thead>
<tbody v-for="user in users">
<td v-text="user.name"></td>
<td v-text="user.username"></td>
<td v-text="user.display_name"></td>
<td class="text-center">
<button
class="letter-shadow btn-sm font-500 grey-darkest roboto letter-spacing"
:class="showRole">Activate
</button>
</td>
</tbody>
</table>
</div>
</template>
<script>
export default {
data() {
return {
users: [],
}
},
computed: {
showRole() {
// wanted to diff button colors here
}
},
mounted() {
axios.get('/api/users').then(response => this.users = response.data);
},
}
</script>
So I wanted to modify that class showRole depending on the value of user.display_name, if the user.display_name is equal to "Manager" e.g. I would show a btn-danger. I just don't know how can I get this value to compare, if I try to use this.user.display_name on showRole method I get nothing (undefined). Thanks for any help.
I think you should use a method instead, as you can't pass parameters to computed properties.
Use this
...
methods : {
showRole(user){
//code that returns the button class
}
}
...
<button :class="showRole(user)">Activate

Using v-bind to put data into a tag a in the property href (VUE.JS 2 + Laravel 5.3)

Here is my javascript/vue.js code:
import _ from 'lodash'
export default{
props:['campanha'],
data (){
return{
list:[],
filter: '',
href: '/campanha/9/edit'
}
},
methods:{
url: function (href){
return '/campanha/'+this.href+'/edit'
}
},
mounted: function (){
this.list = JSON.parse(this.campanha)
},
computed: {
filteredCampanhas(){
var self = this
return this.list.filter(function(campanhas) {
return campanhas.nome.indexOf(self.filter) > -1
})
}
}
}
And here it`s my html:
<template>
<div>
<div class="well">
Novo Cadastro <span class="glyphicon glyphicon-plus" aria-hidden="true"/><br></br>
<input type="text" class="form-control" placeholder="Filtrar Campanhas" v-model="filter">
</div>
<div class="table-responsive">
<table class="table table-borderless">
<thead>
<tr>
<th>Id</th>
<th>Nome</th>
<th>Data Início</th>
<th>Data Término</th>
<th>Hora Inícío</th>
<th>Hora Término</th>
</tr>
</thead>
<tbody>
<!--{{ url('/campanha/' . $item->id_campanha . '/edit') }}
href: '/campanha/9/edit'
<td><a v-bind:href="href">{{ c.nome }}</a></td>
!-->
<tr v-for="c in filteredCampanhas">
<td>{{ c.id_campanha }}</td>
<td><a :href="url(c.id_campanha)">{{ c.nome }}</a></td>
<td>{{ c.data_inicio }}</td>
<td>{{ c.data_termino }}</td>
<td>{{ c.hora_inicio }}</td>
<td>{{ c.hora_termino }}</td>
</tr>
</tbody>
</table>
</div>
<div>
</template>
I have tried to put some data into href section of my tag a, to link to another page, but it`s not working.
Try following:
methods:{
url: function (href){
return '/campanha/'+ href+'/edit'
}
},
When you are using this.href it will start to pick href from data of vue instance,

How to select and deselect an div / button in angularJs?

I am trying to make items not in list but in div and if an item is clicked, the div will be in different colors and the item will be added into a column but if the item is clicked again, the item will changed to original color and in the column the item will be gone. I just can't think how to do it in angular way. I came to another option to be able to add in the column and to remove the item, there's a remove button but I am still curious how the select and deselect can be done.
This is what I have in my html (ignore my btn btn-primary classes I was using button to give it a try in the first place)
<!--Select App Features-->
<div class="panel-heading" ng-controller="FeaturesController as featuresCtrl">
<h1 class="text-center">App Features</h1>
<div class="text-center">
<div ng-repeat="app in featuresCtrl.apps" class="btn btn-primary platform-btn-style" ng-click="featuresCtrl.addPrices(app.name, app.price)">{{ app.name }}</div><br>
</div>
<div>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Device Added</th>
<th>Device Price</th>
<th></th>
</tr>
</thead>
<tr ng-repeat="appList in featuresCtrl.listAppPrices">
<td>{{ appList.name }}</td>
<td>{{ appList.price }}</td>
<td><button class="btn btn-default" ng-click="featuresCtrl.remove($index)">Remove</button></td>
</tr>
</table>
<div>Total : {{ featuresCtrl.totalAppPrice() }}</div>
</div>
</div><!-- end select app features / FeaturesController-->
My controller in js
//Controller for app features
app.controller("FeaturesController", function(){
this.apps = features;
this.listAppPrices = [];
// add name and price into the new array which is used to show in the table
this.addPrices = function(name, price){
//Checks if the exact name, price property exists in the array and return boolean
var found = this.listAppPrices.some(function (e){
console.log(e.name);
return ((e.name === name) && (e.price === price)) ;
});
//If found not true then push the new values into the array
if(!found){
this.listAppPrices.push({name: name, price: price});
}
};
// adds all the prices of the array which gives the total
this.totalAppPrice = function(){
var total = 0;
for(var i = 0; i < this.listAppPrices.length; i++){
total += this.listAppPrices[i].price;
}
return total;
};
// remove the whole object in the array when remove is clicked
this.remove = function(index) {
this.listAppPrices.splice(index, 1);
};
});
I kind of having the idea of how this can be done but I just can't think of the code to write it.
P.S. the codes are simple, I just learned it in code school and wanted to created something for fun to educate myself. Thanks in advance people
angular.module("stack", [])
.controller("FeaturesController", function($scope) {
// this.apps = features;
this.listAppPrices = [];
this.apps = [{ "name": "a1", "price": "12" }, { "name": "a2", "price": "13" }, { "name": "a3", "price": "14" }];
$scope.dummyArray = [];
var f = 0,
x = 0,
rem = false;
this.setSelected = function(app, index) {
console.log("app ", app);
//remove an item
if (app.selected) {
console.log(" list ", $scope.dummyArray);
$scope.dummyArray.forEach(function(e, ind) {
if (e.name === app.name) {
console.log(ind, " e ", e);
rem = true;
$scope.dummyArray.splice(ind, 1);
}
});
console.log("dumm ", $scope.dummyArray);
this.listAppPrices = $scope.dummyArray;
} else {
rem = false;
}
//used to select a div and change its colour
app.selected ? app.selected = false : app.selected = true;
//add an item
if (!rem) {
if ($scope.dummyArray.length) {
$scope.dummyArray.forEach(function(each) {
console.log("each ");
if (each.name !== app.name) {
console.log("inside if ");
f = 1;
}
});
} else {
console.log("inside else ");
$scope.dummyArray.push(app);
}
if (f === 1) {
f = 0;
console.log("push");
$scope.dummyArray.push(app);
}
console.log(" list--> ", $scope.dummyArray.length);
this.listAppPrices = $scope.dummyArray;
}
}
});
.selected {
background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.0/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="stack">
<head>
<title>stack</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="panel-heading" ng-controller="FeaturesController as featuresCtrl">
<h1 class="text-center x">App Features</h1>
<div class="text-center">
<div ng-repeat="app in featuresCtrl.apps track by $index" class="btn btn-primary platform-btn-style" ng-click="featuresCtrl.setSelected(app,$index)" ng-class="{selected: app.selected}">{{ app.name }}</div>
<!-- <div ng-if="(c%2===0)" ng-repeat="app in featuresCtrl.apps" class="btn btn-primary platform-btn-style" ng-click="featuresCtrl.setSelected(app)">{{ app.name }}</div> -->
<br>
</div>
<div>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Device Added</th>
<th>Device Price</th>
<th></th>
</tr>
</thead>
<tr ng-repeat="appList in featuresCtrl.listAppPrices">
<td>{{ appList.name }}</td>
<td>{{ appList.price }}</td>
<td>
<button class="btn btn-default" ng-click="featuresCtrl.remove($index)">Remove</button>
</td>
</tr>
</table>
<div>Total : {{ featuresCtrl.totalAppPrice() }}</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.0/angular.min.js"></script>
<script type="text/javascript" src="controller.js"></script>
</body>
</html>
I haven't added the functionality of remove button.I also haven't count the totalAppPrice. Otherwise your problem is solved :) .

Vue.js $remove not removing element after deleted from database

I am using Laravel and trying to learn Vue.js. I have a delete request that is working properly and deleting the object from the database. The problem is that it is not being removed from the DOM after the successful deletion. I am using the $remove method and passing it the full object, so I know I'm missing something.
As a side note, I have a main.js as an entry point with a PersonTable.vue as a component. The PersonTable.vue holds the template and script for that template.
Here is my Laravel view:
<div id="app">
<person-table list="{{ $persons }}">
</person-table>
</div>
And here is my `PersonTable.vue:
<template id="persons-template">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h1>Persons List</h1>
<table class="table table-hover table-striped">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Email</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
<tr v-for="person in list">
<td>{{person.first_name }}</td>
<td>{{person.last_name }}</td>
<td>{{person.email }}</td>
<td>{{person.gender }}</td>
<td><span #click="deletePerson(person)">X</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
template: '#persons-template',
props: ['list'],
methods: {
deletePerson: function(person) {
this.$http.delete('/person/' + person.id).then(
function(response) {
this.persons.$remove(person);
}
);
}
},
created: function() {
this.persons = JSON.parse(this.list);
}
};
</script>
And my main.js entry point:
var Vue = require('vue');
Vue.use(require('vue-resource'));
var Token = document.querySelector('meta[name="_token"]').getAttribute('content');
Vue.http.headers.common['X-CSRF-TOKEN'] = Token;
import PersonTable from './components/PersonTable.vue';
new Vue({
el: '#app',
components: { PersonTable },
})
I think you need to bind this to the response function:
function(response) {
this.persons.$remove(person);
}.bind(this)
That way when you do this.persons you are still referring to the Vue component
edit: could try -
props:['personJson'],
data:function(){
return {
persons:[]
}
},
ready:function(){
this.persons = JSON.parse(this.personJson)
}
Thinking maybe since persons is a string initially, Vue isn't binding the reactive capabilities properly?
I think that you need to use the this.$set in your created method, if you don't, I am afraid that Vue would lose reactivity.
In your created method, could you try the following:
export default {
template: '#persons-template',
props: ['persons'],
methods: {
deletePerson: function(person) {
var self = this;
this.$http.delete('/person/' + person).then(
function(response) {
self.persons.$remove(person);
}
);
}
},
created: function() {
this.$set('persons',JSON.parse(this.persons));
}
};
Finally figured it out. I needed to pass the JSON data to my data property of the component. Here is the code.
In the blade file:
<div id="app">
<person-table list="{{ $persons }}">
</person-table>
</div>
In my PersonTable.vue file:
<template id="persons-template">
<div class="container">
<div class="row">
<div class="col-sm-12">
<h1>Persons List</h1>
<table class="table table-hover table-striped">
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Email</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
// Notice how I am using persons here instead of list
<tr v-for="person in persons">
<td>{{person.first_name }}</td>
<td>{{person.last_name }}</td>
<td>{{person.email }}</td>
<td>{{person.gender }}</td>
<td><span class="delete person" #click="deletePerson(person)"><i class="fa fa-close"></i></span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
template: '#persons-template',
props: ['list'],
data: function() {
return {
persons: []
}
},
methods: {
deletePerson: function(person) {
this.$http.delete('/person/' + person.id).then(
function(response) {
this.persons.$remove(person);
}
);
},
},
created: function() {
// Pushing the data to the data property so it's reactive
this.persons = JSON.parse(this.list);
},
};
</script>
Thanks to everyone for their contributions. I almost ditched Vue because of how long it has taken to fix this error.

Categories

Resources