I have this code and I get an array in the info variable. The problem is in the delete button that calls the remove function passing the id as a parameter but it passes the first id to all elements so when I delete any element it deletes the first one instead of referring to the button
<tr>
<th scope="row">{{info.product_key}}</th>
<td>{{info.name}}</td>
<td>{{info.quantities}}</td>
<td>{{info.quatities_sold}}</td>
<td>{{info.cost_price}}</td>
<td>{{info.sale_price}}</td>
<td><button #click="showEditModal" class="btn btn-warning">editar</button></td>
<EditProductModal
:_id=info._id
:product_key=info.product_key
:product_name=info.name
:quantities=info.quantities
:quantities_sold=info.quatities_sold
:cost_price=info.cost_price
:sale_price=info.sale_price
:categories=info.categories
/>
<td><button #click="remove(info._id)" class="btn btn-danger">excluir</button></td>
</tr>
</tbody>```
As you said I get an array in the info variable but looks like instead of iterating you are directly using it. If you are iterating it properly using v-for it should pass the correct ID.
Working Demo :
const app = new Vue({
el: '#app',
data: {
info: [{
'_id': 1,
'name': 'alpha'
}, {
'_id': 2,
'name': 'beta'
}, {
'_id': 3,
'name': 'gama'
}]
},
methods: {
remove(itemID) {
console.log(itemID);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table>
<tr v-for="item in info" :key="item._id">
<td>{{item.name}}</td>
<td><button #click="remove(item._id)">excluir</button></td>
</tr>
</table>
</div>
Related
I get a nested JSON object back from an API call that looks something along the lines of this:
{
"name": “Main “Folder”,
"children": [
{
"name": “Child Folder 1”,
"children": []
},
{
"name": “Child Folder 2”,
"children": [
{
"name": “Sub Folder 1”,
"children": [
{
“name”: “Sub Sub Folder 1”,
“children”: []
}
]
},
{
"name": “Sub Folder 2” ,
"children": []
}
]
}
]
}
There is no limit on how far the JSON object can be nested so that is unknown to me. I need to have all of the children of the folders to be indented under the parent in the table. I'm not really even sure how to go about doing this. The first thing I tried was doing something like this in my HTML file, but I quickly realized it wasn't going to work.
folders.html
<table>
<thead>
<tr><strong>{{ this.tableData.name }}</strong></tr>
</thead>
<tbody ng-repeat="b in this.tableData.children">
<tr>
<td>{{ b.name }}</td>
<td ng-repeat="c in b.children">{{ c.name }}</td>
</tr>
</tbody>
</table>
folders.js
export default class FoldersController {
constructor($rootScope, $scope, $uibModal) {
this.tableData = {Example Data from top}
}
}
Is there a not too complicated way to go about doing this? Thanks!
You should create a component with a template that contains a table, then you can nest your component inside itself to follow the tree structure logical path:
Your root controller should contain your table data:
angular.module('app').controller('RootCtrl', ['$scope', function($scope) {
// assigning the data to $scope to make it available in the view
$scope.tableData = {Example Data from top};
}]);
Your tree component could be something on this lines:
angular.module('app').component('treeComponent', {
controller: 'TreeCtrl',
bindings: {
tree: '<',
},
templateUrl: 'tree-view.html'
});
your root template should load the first instance of the component:
<div>
<tree-component tree="tableData"></tree-component>
</div>
then the component template should take care of the the recursion when required;
tree-view.html:
<table class="record-table">
<thead>
<tr>
<th>
<strong>{{ $ctrl.tableData.name }}</strong>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="node in $ctrl.tableData.children">
<td>{{node.name}}</td>
<td ng-if="node.children.length > 0">
<tree-component tree="node.children"></tree-component>
</td>
</tr>
</tbody>
</table>
creating indentation then becomes easy using basic css:
.record-table .record-table {
padding-left: 20px
}
I was able to figure out a solution of my own using recursion in the js file. I implemented mindthefrequency's answer as well and it seems to be working just fine. I'm marking it as the best answer because it seems to be the cleaner solution, but I'm posting what I have in case someone wants to take a more js oriented approach.
First, in the js file, use recursion to add all of the nodes and how far each needs to be indented to the table data variable.
folders.js
export default class FoldersController {
constructor($rootScope, $scope, $uibModal) {
this.resp = {Example Data from top}
this.tableData = []
this.createTable(this.resp.children, 0, [
{
name: this.resp.name,
indent: '0px',
},
]);
}
createTable(children, count, data) {
count += 1;
// base case
if (!children || children.length === 0) {
return;
}
for (const child of children) {
const { name } = child;
const returnData = data;
returnData.push({
name: name,
indent: `${count * 25}px`,
});
this.tableData = returnData;
this.createTable(child.children, count, returnData);
}
}
}
Then, in the html file, use angularjs to properly indent each node
folders.html
<table>
<thead>
<tr><strong>Table Header</strong></tr>
</thead>
<tbody ng-repeat="b in vm.tableData">
<tr>
<td ng-style="{'padding-left': b.indent}">{{ b.name }}</td>
</tr>
</tbody>
</table>
I can get the elements sent from the backend.But the text can't display.I don't know why.
here is my html :
<!-- <form action=""> -->
<div class=" form-group">
<input v-model="wd" #keyup="keyup($event)" type="text" class="form-control" />
<!-- <ul class="list-group"> -->
<table>
<tr>
<th v-for="item in title"><div style="width:500px">{{item}}</div> </th>
</tr>
<tr v-for="item in arr" :key='item'>
<td>{{item.name}}</td>
<td>{{item.sort}}</td>
<td>{{item.company}}</td>
</tr>
</table>
</div>
here is My Vue:
el: "#app",
data: {
wd: '',
arr: [],
listIndex: -1,
title:['name','sort','company'],
},
methods: {
keyup(event) {
var url = "/search/search/"
axios.get(url, {
params: {
q: this.wd,
}
}).then(res => {
console.log(res);
this.arr = res.data.list;
})
}
}
})
;
I know the data was got.Because the number of the items in loop is exactly correct.When I console.log(res.data.list),I can view the data from the backend.But they can't display in my page.
I will be very appreciate it if you could help me.Thank you!
enter image description here
I think the problem is in your reference to this.arr in your callback. When the AJAX call returns, this is scoped to the response, not your Vue object.
You can overcome this by inserting a variable prior to the AJAX call, like this:
var vm = this;
axios.get(url, {
then, in the callback, instead of this.arr = res.data.list;, do this:
vm.arr = res.data.list;
The field data must be reactive
data() {
return{
wd: '',
arr: [],
listIndex: -1,
title:['name','sort','company'],
}
}
I'm trying to parameterise variable names so they can be passed as properties into my component. In the example below I want to use this to pass the names of the item variables into the array so I can selectively display them as columns in a table without the binding having to know the item variable names.
<div id="myApp">
<h2>parameterized variable names</h2>
<table>
<tr>
<th v-for="label in labels">{{label}}</th>
</tr>
<tr v-for="item in items">
<td v-for="label in labels">{{item.label}}</td>
</tr>
</table>
</div>
My Vue instance looks like this -
new Vue({
el: '#myApp',
data: {
labels:[
'text',
'value'
],
items:[
{text: 'One', value: 'A', something:'12'},
{text: 'Two', value: 'B', something:'67'},
{text: 'Three', value: 'C', something:'66'}
]
}
});
This doesn't work because it is attempting to render a variable called 'label' in the declaration {{item.label}}. How can I tell it that 'label' is not the literal variable name?
You can use array syntax in Vue.js templates, so the following should work:
<td v-for="label in labels">{{ item[label] }}</td>
Here table contains book details which contains book name, author, pric, ISBN and category. When user click on Book Name it should pass the data to another page using querystring
<script type="text/javascript" src="book.js">
<body ng-app="mymodule" >
<div ng-controller="myController" >
<table border=2>
<thead>
<tr>
<th>ISBN</th>
<th>NAME</th>
<th>AUTHOR</th>
<th>CATEGORY</th>
<th>PRICE</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="book in books">
<td>{{ book.ISBN }}</td>
<td >{{ book.Name }}</td>
<td>{{ book.Author }}</td>
<td>{{ book.Category }}</td>
<td>{{ book.price }}</td>
</tr>
</tbody>
</table>
books.js
var myapp = angular.module('mymodule', []);
myapp.controller("myController", function($scope, $http,$window) {
$http.get("https://api.myjson.com/bins/p4ujn").then(function(response) {
$scope.books = response.data;
$scope.getdetail=function(){
$scope.getbookdetail=this.book;
$window.location.href = "orderpage.html";
}
});
});
orderpage.html
<script type="text/javascript" src="book.js"></script>
<body ng-app="mymodule" >
<div ng-controller="myController" >
{{getbookdetail.Name}}<br>
{{getbookdetail.Author}}
{{getbookdetail.price }}<br>
</div>
</body
So you said this: 'When user click on Book Name it should pass the data to another page using querystring'
Querystring is not the best method to use for something like this. You're better off learning about ui-router and setting up routes that handle this. You have your initial state, then you can create another state to display each book. Something like this:
.state('initial', {
url: 'some/initial',
template: 'some/initial/template.html',
params: {
name: null,
price: null,
author: null,
isbn: null,
category: null
}
})
.state('read-book-details', {
parent: 'initial',
url: 'some/url',
template: 'some/template.html',
params: {
name: null,
price: null,
author: null,
isbn: null,
category: null
}
})
Then when you're transitioning from one 'state' to another, you do it like so passing along the parameters you want:
$state.go('read-book-details',
{ name: book.name, price: book.price, author: book.author });
On the 'other' page's controller (ie the controller for the 'read-book-details' state) you can inject $state and get the parameters that are passed in via $state.params (ie., $state.params.price)
A second option for you is to have a service that you can store the data in, then retrieve from anywhere else. This obviously becomes useful when you start to pass around larger amounts of data rather than simpler smaller pieces (like name, price).
I have to render a table with dynamic headers, I mean, I don't want to do something like this in the HTML
<table>
<tr>
// THIS TABLE ROW IS WHAT I SAY
<th>here info</th>
<th>something here</th>
<th>another header</th>
</tr>
<tr ng-repeat="thing in things">
<td>{{thing.asfs}}</td>
<td>{{thing.asx}}</td>
<td>{{person.dsf}}</td>
</tr>
</table>
I want something like this
<table>
<tr ng-repeat="head in heads">
{{head}}
</tr>
<tr ng-repeat="bar in bars">
<td ng-repeat="foo in foos"></td>
</tr>
</table>
that is only an example, I need to do it with this data:
{
"55f6de98f0a50c25f7be4db0":{
"clicks":{
"total":144,
"real":1
},
"conversions":{
"total":4,
"amount":229
},
"cost":{
"cpc":0.1999999999999995,
"ecpc":1145.0000000000027,
"total":28.79999999999993
},
"revenue":{
"total":4,
"epc":0.027777777777777776
},
"net":{
"roi":-1.1612903225806457,
"total":4
},
"name":"Traffic Source #2",
},
"55f6de98f0a50c25f7be4dbOTHER":{
"clicks":{
"total":144,
"real":1
},
"conversions":{
"total":4,
"amount":229
},
"cost":{
"cpc":0.1999999999999995,
"ecpc":1145.0000000000027,
"total":28.79999999999993
},
"revenue":{
"total":4,
"epc":0.027777777777777776
},
"net":{
"roi":-1.1612903225806457,
"total":4
}
"name":"Traffic Source #3"
},
}
every key, like clicks, conversions, cost, etc, should be a td, it is just that I don't want static HTML.
Any suggestions?
EDIT
And also, sometimes that object will grow, could come up with some more keys like this one 55f6de98f0a50c25f7be4db0
I did this fiddle with the exact same data I am receiving
http://jsfiddle.net/wLkz45qj/
UPDATE:
What you need to do is first convert you inconvenient object to array of objects with simple structure, and then use my code , i.e.
{
a: {
b:{
c: 'x'
}
}
}
will turn into
[[ a, { 'b.c' : 'x' }], ...]
or just
[{ _id : a , 'b.c' :'x'}, ...]
easiest way to do that is to use lodash or underscore ( check map, flatMap, pairs etc)
#jperezov showed you core idea, little bit detailed example:
$scope.peopleKeys = Object.keys(people[0])
and
<table>
<tr>
<th></th>
<th ng-repeat="personKey in peopleKeys">
{{ personKey }}
</th>
</tr>
<tr ng-repeat='p in people'>
<th>{{ $index }}</th>
<td ng-repeat="personKey in peopleKeys">
{{ p[personKey] }}
</td>
</tr>
</table>
You may also have some dictionary with display names:
$scope.displayNames = {
id: 'ID',
firstName: 'First Name'
...
}
and then your header going to be:
<tr>
<th></th>
<th ng-repeat="personKey in peopleKeys">
{{ displayNames[personKey] }}
</th>
</tr>
PS: OR you can just use ui-grid
var app = angular.module('myApp', []);
function PeopleCtrl($scope, $http) {
$scope.headers=[];
$scope.data = [];
$scope.LoadMyJson = function() {
for (var s in myJson){
$scope.data.push(s);
if ($scope.headers.length < 1)
for (var prop in myJson[s]){
prop.data = [];
$scope.headers.push({th:prop, td: []});
}
}
for (var s in $scope.data){
for (var prop in $scope.headers){
var header = $scope.headers[prop].th;
var data = myJson[$scope.data[s]][header];
$scope.headers[prop].td.push(data);
}
}
};
}
What you're looking for is something like this, I think:
http://jsfiddle.net/wLkz45qj/8/
Maybe iterate another time over "inner" for formatting.