Basically I'm making a todo list with angular and I want to display the how many items have been marked as done I have an array object of Lists and each list has a collection of list items called todos like so:
[{listName: "ESSENTIALS", newTodoName:"", newTodoQ:"0", todos: [
{ taskName : "Comb" , quantity: 1, isDone : false , id: "comb" } ]},
{listName: "TOILETRIES", newTodoName:"", newTodoQ:"0", todos: [
{ taskName : "Tooth Brush" , quantity: 1, isDone : false , id: "toothbrush"},
{ taskName : "Tooth paste" , quantity: 6, isDone : false, id: "toothpaste" },
{ taskName : "Deodorant" , quantity: 3, isDone : false, id: "deodorant" }
]}];
So I have two ng-repeats.. One repeats the Lists then another inside of it prints out each list item. I have an H1 and next to the title I want to have the the items that were marked isDone as true next to the total amount of records to show how many items you have left. As you can see I started to code up a filter but I believe it's wrong I keep getting: "Syntax Error: Token 'undefined' is unexpected, expecting [}] at column null of the expression [ (list.todos |] starting at [{4}]." which I'm not really sure what that means...my fourth item is blank? Yet I have all my todos there and they are not blank. Is my filter wrong? or a better way to do this?
<div class='row' ng-repeat="list in lists">
<h1 class='centerTitle'>{{list.listName}} <span class="listCounter"> {{ (list.todos | filter:{todos: {isDone: true}}: true).length }} / {{list.todos.length}}</span></h1>
<ul ui-sortable="todoSortable" ng-model="list.todos">
<li ng-class="{taskDone: todo.isDone}" class="todoTask" ng-repeat="todo in list.todos | orderBy: 'isDone' "></li>
<div>
Can you try:
<h1 class='centerTitle'>{{list.listName}} <span class="listCounter"> {{ (list.todos | filter: {isDone: true}).length }} / {{list.todos.length}}</span></h1>
Related
So I searched for similar question and I applied their answers but it doesn't seem to work in my case. It's frustrating 'cause it should be something simple.
So, I use mustache template to render data that come from a node server with sockets.
It works fine with one object but when I try to iterate through an array of object it just render a blank page.
This is my socket, the push is just to simulate what I'm gonna do next (get a new object in the array)
let productsTab = [{
prodName: prodName,
prodPrice: prodPrice,
quantity: quantity,
quantityUnit: quantityUnit,
isQuantityManual: isQuantityManual,
hasQuantityUnit: hasQuantityUnit,
totalPrice: totalPrice
}];
productsTab.push({
prodName: prodName,
prodPrice: prodPrice,
quantity: quantity,
quantityUnit: quantityUnit,
isQuantityManual: isQuantityManual,
hasQuantityUnit: hasQuantityUnit,
totalPrice: totalPrice
});
res.render('displayProduct', productsTab);
this is the log of my array
[
{
prodName: 'name',
prodPrice: 'price',
quantity: '1',
quantityUnit: '',
isQuantityManual: false,
hasQuantityUnit: false,
totalPrice: 'price'
},
{
prodName: 'name',
prodPrice: 'price',
quantity: '1',
quantityUnit: '',
isQuantityManual: false,
hasQuantityUnit: false,
totalPrice: 'price'
}
]
And finally this is my mustache template
{{#productsTab}}
<div>
<div>
{{ prodName}}
</div>
<div>
{{{ prodPrice }}}
{{ #hasQuantityUnit }}
text
{{ /hasQuantityUnit }}
</div>
</div>
<div>
<div>
x {{ quantity }} {{ quantityUnit }}
{{ #isQuantityManual }}
(MAN)
{{ /isQuantityManual }}
</div>
<div>
= {{{ totalPrice }}}
</div>
</div>
{{/productsTab}}
It works fine with just an object (not an array) without the {{#}} loop feature so the issue must come from the array...
I need some help please
Ok, I got it. It is when I render my template
res.render('displayProduct', productsTab);
This works only when the props you pass is an object but I had to iterate through an array of object so I did this :
res.render('displayProduct', { productsTab });
Hope it will help someone that got a brain freeze like me.
Please find below a simplified example of what I try to achieve.
I have a big list of which I create an overview using alpinejs.
I now added a filter to just show some of my elements.
I also have a global number of elements shown as well as a global count of stuff the elements have.
In below example I show for each client the cars they own and the number of cars they own. Globally I show the number of clients and the total amount of cars.
This works as long as I do not filter.
As soon as filtering starts, the global numbers act weird.
When started, I have 3 clients and 5 cars.
When I enter an E, It should be 1 client and 2 cars, but it remains as 3 and 5.
When I remove the E, the numbers go up to 8 clients and 12 cars.
I'm sure it is due to the fact that the global counts do not get reset to 0.
But I couldn't find a way to achieve this reset. Any help would be much appreciated.
Please note that I know, I can avoid actually counting the cars with ++individualcount by just replacing x-text="individualcount" with x-text="cars.length".
<html>
<head>
<script defer src="https://unpkg.com/alpinejs#3.x.x/dist/cdn.min.js"></script>
</head>
<body>
<h1 x-data="{ message: 'I ❤️ Alpine' }" x-text="message"></h1>
<div
x-data="{
search: '',
items: [
{client: {name: 'Hugo', id:'0001' }, stuff: {cars: [ 'Horch', 'Benz' ] } },
{client: {name: 'Hans', id:'0002' }, stuff: {cars: [ 'Horch' ] } },
{client: {name: 'Egon', id:'0003' }, stuff: {cars: [ 'VW', 'Maybach' ] } },
],
get filteredItems() {
return this.items.filter(
i => i.client.name.startsWith(this.search)
)
},
}"
>
<input x-model="search" placeholder="Search...">
<ul x-data="{ clientcount : 0, carcount : 0 }">
<p>Number of clients: <span x-text="clientcount"></span></p>
<p>Number of cars: <span x-text="carcount"></span></p>
<template x-for="item in filteredItems" :key="item.client.name">
<li x-data="{ individualcount : 0 }"
x-effect="carcount += individualcount; ++clientcount">
<span x-text="item.client.id"></span>
<span x-text="item.client.name"></span>
(<span x-text="individualcount"></span>)
<ul>
<template x-for="car in item.stuff.cars" :key="car">
<li x-text="car"
x-effect="++individualcount">
</li>
</template>
</ul>
</li>
</template>
</ul>
</div>
</body>
</html>
I have a input (top right) where users can search things, when it's directive length get 3 characters it will display a list of products and highlight the matches...
Look at my code:
html
<div id="app">
<div id="header">
<div class="right"><input type="text" v-model="message" v-on:keyup="searchStart()" v-on:blur="searchLeave()"/>
<ul v-if="this.searchInput" class="product-list">
<li v-for="product in products">
{{ product.id }} - {{ product.name | highlight }} - {{ product.qtd }}</li></ul>
</div>
</div>
<div id="main">
<div id="menu">fdfds</div>
<div id="container">{{ message }}</div>
</div>
</div>
js
var search = new Vue({
el: "#app",
data: {
message: "",
searchInput: false,
products: [
{
id: 1,
name: "produto 01",
qtd: 20
},
{
id: 2,
name: "produto 02",
qtd: 40
},
{
id: 3,
name: "produto 03",
qtd: 30
},
]
},
methods: {
searchStart: function(){
if(this.message.length >= 3)
this.searchInput = true;
console.log(this.searchInput);
},
searchLeave: function(){
this.searchInput = false;
this.message = "";
console.log(this.searchInput);
}
},
filters: {
highlight: function(value){
return value.replace(search.message, '<span class=\'highlight\'>' + search.message + '</span>');
}
}
});
Here you can see a live pen: http://codepen.io/caiokawasaki/pen/dXaPyj
try to type prod inside the pen...
Is my filter correct? The way I created the filter is correct?
The main question is: How to output the HTML from my filter?
Edit/Solution
The problem in the case was codepen, there is some kind of conflict with vue, so I was not able to escape the html using {{{}}}, put the code in another editor (jsfidle) and it worked.
I'm accepting the answer given to the reward because it's right.
You'll need 3 steps here for achieve what you want:
Use triple braces {{{ }}} to display unescaped html
Filter your users by your v-model variable, in order to just show the matches
Replace the substring matching by the <span> tag
Check out the computed property filteredUsers and the filter in this working jsfiddle
So I have an array called domains which returns a variation of data, among which is a category spanding from 0-12.
It looks something like:
domains: {
0 {
available : true
category : 0
}
1 {
available : true
category : 1
}
2 {
available : true
category : 2
}
3 {
available : true
category : 3
}
4 {
available : true
category : 4
}
}
Then I have the following keys:
categoryLabels {
0 : Professional
1 : Government
2 : Finance
3 : Business
4 : Colors
}
Now what I would like to do is to display the matchin category with the matching categoryLabel
I have tried this but it doesnt seem to work:
for (key in this.categoryLabels) {
var item = {
name: key, // Push the key on the array
value: this.categoryLabels[key] // Push the key's value on the array
};
return this.categoryName;
console.log(this.categoryName.value);
}
Does anyone have a solution ?
I tweaked your sample data assuming you are having a valid Data .
view:
<div data-bind="foreach:dom.domains">
<p> available</p> : <b data-bind="text:available"></b>
<p> category </p> : <b data-bind="text:ctgry.categoryLabels[category]">
</div>
code:
var dom = {
'domains': [{
'available': true,'category': 0}, {'available': true, 'category': 1 },{'available': true,'category': 2 },{ 'available': true,'category': 3},{'available': true, 'category': 4
}]
};
var ctgry = {
'categoryLabels': { 0: 'Professional',1: 'Government', 2: 'Finance',3: 'Business',4: 'Colors',
}
}
ko.applyBindings({ //pass your json data here
dom,
ctgry
});
sample fiddle up for grabs
PS: Instead of passing json data directly to ko,however you can have your viewModel created and store it in observable & bind to view.
I am following this question to filter ng-repeat by a field
ng-repeat :filter by single field
However my case is different, it's actually a field in the object value of the main object. Basically I want to show only data.a == 1
The following code works on the first list. The second list gives me error:
angular.module('myapp', [])
.controller('mainCtrl', function ($scope) {
$scope.items = [{
name: "John",
data: {
a: 1
}
}, {
name: "Lee",
data: {
a: 2
}
}, {
name: "Rue",
data: {
a: 3
}
}, {
name: "Peter",
data: {
a: 1
}
}];
});
HTML
<div ng-controller="mainCtrl">
<h1>List 1</h1>
<p ng-repeat="item in items">{{ item.name }}</p>
<h1>List 2</h1>
<p ng-repeat="item in items | filter: {data.a :1}">{{ item.name }}</p>
</div>
http://plnkr.co/edit/nh4GryqZJbEiXSzMzTKk
Any help on how to do this or is there a nicer way?
UPDATE 1
I tried angular.filter filterBy and it didn't work either. Giving me blank array.
http://plnkr.co/edit/nh4GryqZJbEiXSzMzTKk?p=preview
<p ng-repeat="item in items | filterBy: ['item.data.a'] :1">{{ item.name }}</p>
UPDATE 2
I tried this below
<p ng-repeat="item in items | filter: {data :{a:1}}">{{ item.name }}</p>
It seems to work but I need exact match, not substring match. I read this but not seem to find a way to add true AngularJS Filter Exact Match
Any clue?
UPDATE 3 (CORRECT ANSWER):
This works http://plnkr.co/edit/qJl6MtY6fOlVtD9Rv999?p=preview
Basically I added this to the controller
$scope.filteredItems = $filter('filter')($scope.items, {data :{a:1}}, true);
and do ng-repeat on filteredItems instead. I don't see a way to pass true param in the view directly.
If you want to access the inner property you need to access it with object notation:
<p ng-repeat="item in items | filter: {data :{a:1}}">{{ item.name }}</p>
Check this plunker.
If you are using \ can upgrade to angular 1.3, then you can use this: 1.3 filters These are faster. In particular, you can use filterBy
See: plunkr example
<p ng-repeat="item in items | filterBy: ['data.a'] :1">{{ item.name }}</p>
Otherwise, use a custom function. See my answer here: custom function