I'm currently learning Javascript (VueJS) and updated one of my existing Laravel apps. It worked pretty well so far. Still I'm in trouble at one point: I have two props (e.g. prop1 and prop2) and want to render an entry in a table differently, if a value in prop1 is also present in prop2, meaning the value is somewhere in prop2. Look at this sample code:
<tr v-for="s in list">
<td v-if="s.value1 is also present in prop2"><i class="fa fa-circle text-danger"></i></td>
<td v-else><i class="fa fa-circle text-success"></i></td>
<td>{{ s.value1 }}</td>
<td>{{ s.value2 }}</td>
</tr>
Is there a nice and short "vue-like" way to do this?
You can use the .some operator to check if a value is present in another array:
// Will return true if any items matches s.value1
prop2.some(function (item) {
return item === s.value1
});
You can add it to your Vue instance as a method or a computed property, for example:
var app = new Vue({
el: "#vue",
data: {
prop2: []
},
methods: {
checkProp2: function(val) {
return prop2.some(function (item) {
return item === val;
})
}
}
})
Then you can do something like:
<tr v-for="s in list">
<td v-if="checkProp2(s.value1)"><i class="fa fa-circle text-danger"></i></td>
<td v-else><i class="fa fa-circle text-success"></i></td>
<td>{{ s.value1 }}</td>
<td>{{ s.value2 }}</td>
</tr>
<td v-if="s.value1 === s.value2">
Related
I've found many resources for sorting data that is already in an array but can't find anything on sorting dynamically generated data.
<table>
<thead>
<tr>
<th>Program</th>
<th>Rewards</th>
</tr>
</thead>
<tbody>
<tr v-for="program in programs" :key="program.id">
<td>{{ program.program_name }}</td>
<td>{{ pointValue(program) | percent }}</td>
</tr>
</tbody>
</table>
pointValue() is a method which calculates and returns a value which is displayed as a %. this is the Rewards column. i would like the table to be sortable by Programs and by Rewards. (Program is just a string).
Create computed array for programs using map and sort method and iterate it instead
computed: {
computedPrograms() {
return this.programs
.map(program => {
return {
...program,
value: this.pointValue(program)
}
})
.sort((a, b) => a.value - b.value)
}
}
<tr v-for="program in computedPrograms" :key="program.id">
<td>{{ program.program_name }}</td>
<td>{{ program.value | percent }}</td>
</tr>
This is how I display it
<tr v-for="(foodItem, index) in filteredFoodItems">
<td>{{ foodItem.name }}</td>
<td>{{ foodItem.price | currency('£') }}</td>
<td>{{ foodItem.category }}</td>
<td><a #click="removeItem(index)" class="button is-danger is-outlined">
<span>Delete</span>
<span class="icon is-small">
<i class="fas fa-times"></i>
</span>
</a>
</td>
</tr>
This is what I use to delete
router.delete('/', function (req, res) {
let itemToRemove = req.body;
let FoodItem = mongoose.model('FoodItem', FoodItemSchema);
FoodItem
.find(itemToRemove)
.remove(itemToRemove, err => {
if (err) return handleError(err);
})
})
When I clicked the button it deleted the whole database data instead of the selected item in the database. In the v-for I put index so that each food item has an index and then on the #click I put removeItem(index) so it refers to that one but it has deleted the whole database? Can anyone spot what I have done wrong? thanks in advance!
Here is the removeItem
removeItem(itemToRemove) {
axios.delete('/api/menu', this.foodItems[itemToRemove])
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err)
});
}
},
In your router code you rely upon the response body to determine what to delete. Yet in your axios code you don't load the response body, you only supply an array element. So...
Change
axios.delete('/api/menu', this.foodItems[itemToRemove])
To
axios.delete('/api/menu', {data:this.foodItems[itemToRemove]})
that simple change should work for you.
Everything looks fine. Though, you need to use :key binding so that index would be respected while rendering the list:
<tr v-for="(foodItem, index) in filteredFoodItems" :key="index">
Also, you have link tag and using click handler on it should be prevented it's default:
#click.prevent="removeItem(index)"
Im trying to display a json object using angular. the object may have nested object or not, so i need to evaluate in runtime.
The logic is as follows :
for each key-val (k,v):
if v is an object then: for each (k2,v2) add another nested table in the HTML_TD. if not - need to print the value in a HTML_TD
The nested object works.
The problem : when v is an object i expect the expression to evaluates to '' and print nothing (because im going to an inner loop k2,v2) but instead, even if v is an object, it print it out to the HTML_TD
code :
<table border="1">
<tr ng-repeat="(k,v) in json.properties">
<td> {{ k }} </td>
<td> {{ typeof (v) == 'object' ? '' : v }} </td>
<td>
<table>
<tr ng-repeat="(k2,v2) in v">
<td> {{ k2 }} </td>
<td> {{ v2 }} </td>
</tr>
</table>
</td>
</tr>
The typeof function is not defined on angularjs template interpolation, the template syntax is a bit limited in terms of javascript functions but you can declare it on your scope like so:
$scope.typeof = function(obj) {
return typeof(obj);
};
So that a function named typeof will be visible on your scope and your snipet will be able to get working. The bellow snipet is a simple example implementing this solution.
angular.module('myApp', [])
.controller('myController', function($scope) {
$scope.json = {
properties: {
a: 'A',
b: 'B',
c: {
a1: 'A1'
}
}
};
$scope.typeof = function(obj) {
return typeof(obj);
};
});
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.js"></script>
<div ng-controller="myController">
<table border="1">
<tr ng-repeat="(k,v) in json.properties">
<td>{{ k }}</td>
<td>{{ typeof(v) == 'object' ? '' : v }}</td>
<td>
<table border="1">
<tr ng-repeat="(k2,v2) in v">
<td>{{ k2 }}</td>
<td>{{ v2 }}</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
I think angular parser don't allow typeof function in template.
But you can define one method in controller to get typeof.
E.g.:
$scope.getTypeof = function(value) {
return typeof value;
};
Now call this method in template code:
{{ getTypeof(v) === 'object' ? '' : v }}
im using ngTable. Sorting is not working.
Pagination works nice and it shows all my data as I need. But I can't sort.
I'm using $data (I dont know what is for) but still can't sort.
My html:
<div class="panel-heading">
<table ng-table="vm.tableParams">
<tbody>
<tr ng-repeat="event in $data">
<td data-title="'Nombre'" sortable="'name'"> {{ event.phone ? "Tex1" : Text2 }}</td>
<td data-title="'Dia Entero'" sortable="'entero'">{{ event.allDay ? '√' : 'X' }}</td>
<td data-title="'F. Inicio'" sortable="'inicio'">{{ event.start | date:'dd-MM-yyyy' }}</td>
<td data-title="'F. Fin'" sortable="'fin'"> {{ event.end | date:'dd-MM-yyyy' }}</td>
<td data-title="'Telf.'" sortable="'telf'"> {{ event.phone ? event.phone : '--' }}</td>
</tr>
</tbody>
</table>
</div>
My js:
// My data
[{
"title":"Cerrado",
"start":"2015-12-24T23:00:00.000Z",
"allDay":true,
"backgroundColor":"#f05050",
"borderColor":"#f05050"
},
{
"title":"Abierto",
"start":"2016-04-10T04:00:00.000Z",
"end":"2016-04-10T08:00:00.000Z",
"backgroundColor":"#43d967",
"borderColor":"#43d967"
},
{
"title":"Mi Guardia",
"start":"2015-12-24T01:00:00.000Z",
"end":"2015-12-24T08:00:00.000Z",
"backgroundColor":"#5d9cec",
"borderColor":"#5d9cec"
},
{
"title":"super farmacias",
"phone":"677889966",
"address":"Calle badajoz 200",
"start":"2016-01-06T02:00:00.000Z",
"end":"2016-01-06T09:00:00.000Z",
"backgroundColor":"#dde6e9",
"borderColor":"#dde6e9",
"textColor":"#555"
}]
var data = vm.events;
vm.tableParams = new ngTableParams({
page: 1, // show first page
count: 8, // count per page
sorting: {
name: 'asc'
}
},
{
total: data.length,
counts: [],
getData: function($defer, params) {
// use build-in angular filter
var orderedData = params.sorting() ?
$filter('orderBy')(data, params.orderBy()) :
data;
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
I have been trying for 2 hours with a lot of examples and changing $data for vm.values and creating other variables and stuffs.
Any idea why sort is broken?
Thanks
After checking your data, you have to modified the HTML code sortable = the object key.
Because when you sort some data in the table using ng-table, it is based on what data is displaying in the table. In this case, it will be the data you just posted. And in your data, you don't have a field called name, entero and etc. Therefore, the sort function is not working for you.
<tr ng-repeat="event in $data">
<td data-title="'Nombre'" sortable="'title'"> {{ event.phone ? "Tex1" : Text2 }}</td>
<td data-title="'Dia Entero'" sortable="'allDay'">{{ event.allDay ? '√' : 'X' }}</td>
<td data-title="'F. Inicio'" sortable="'start'">{{ event.start | date:'dd-MM-yyyy' }}</td>
...
</tr>
Usually for sorting, reverseSort feature is handy, Please try this to sort
<th>Field Name</th>
I have two <tr>s and an ng-repeat on each, but both perform the same operation on their child elements, like so:
<tr ng-repeat="item in data : filterFunc" ng-if="mode === 'something'">
<td>{{item.name}}</td>
</tr>
<tr ng-repeat="item in data : filterFunc" ng-if="mode === 'somethingelse'">
<td>{{item.name}}</td>
</tr>
Imagine, there are two types of data sets and which one is to be rendered is decided by the mode property at run time. So, either the first <tr> is rendered in the DOM or the other one.
Initially the first <tr> will be rendered and the associated filterFunc function will work properly. There's a simple drop down which has two options, one each for the two modes. If you select the other mode, the second <tr> will be rendered and first one will be removed from the DOM.
The problem is, the filterFunc now is bound to both the <tr>s and operates on both of them.
How do I unbind the scope or watchers for the first one let it be bound only to the second one? or any one of them at any point of time? Here's the fiddle http://jsfiddle.net/6kx4ojL4/
Note: For the sake of simplicity, I have simply returned the passed-in data object as-is in filterFunc. Check the output in browser console. It gets called twice, i.e. for both data sets.
It is not clear what you want to do exactly from your description. My first thought is that you could separate your modes in ng-if, say, use mode1 and mode2, so you can control two <tr>s separately..
Use ng-show instead of ng-if
<tr ng-repeat="item in data : orderBy: 'name'" ng-show="mode === 'something'">
<td>{{item.name}}</td>
</tr>
<tr ng-repeat="item in data : orderBy: 'name'" ng-show="mode === 'somethingelse'">
<td>{{item.name}}</td>
</tr>
How about this. Check this JSFiddle: http://jsfiddle.net/vxcjw45d/1/
If it's not what are you looking for tell me - I will delete it :)
HTML:
<body ng-app="myApp">
<table ng-controller="myController">
<tr ng-repeat="item in data | orderBy: 'name'"
ng-if="mode === 'something'">
<td>{{ item.name }}</td>
</tr>
<tr ng-repeat="item in data | orderBy: 'name'"
ng-if="mode === 'somethingelse'">
<td>{{ item.age }}</td>
</tr>
<tr>
<td>
<button ng-click="changeMode()">
Change Mode
</button>
</td>
</tr>
</table>
</body>
JS:
var myApp = angular.module('myApp', []);
myApp.controller('myController', function($scope) {
$scope.data = [
{ name: 'John', age: 21 },
{ name: 'Doe', age: 33 }
];
$scope.mode = 'something';
$scope.changeMode = function() {
if ($scope.mode === 'something') {
$scope.mode = 'somethingelse';
} else if ($scope.mode === 'somethingelse') {
$scope.mode = 'something'
}
};
});