Two way binding with pipe not binding in angular2 - angularjs

In my component html displaying the data based on the current year using the filter, it works fine on load. If i do push or pop on the variable updating the html also, but i use filter (pipe) not updating the html view.
onSubmit pushing the new data value to the projects (appropriate), it's reflecting (updating the html) If didn't use filter.
data.component.ts
constructor() {
this.projects = (from service getting the data);
var newDate = new Date();
newDate.setDate(1);
this.dateValue = newDate;
}
onSubmit(data) {
this.projects.push(data);
}
data.component.html
<ul class="list-group">
<li *ngFor="let event of projects | yearFilter: dateValue" class="list-group-item">
<span class="event_release">{{event.startDate | date: 'dd/MM/yyyy'}} </span><br />
<strong>{{event.title}}</strong>
</li>
</ul>
<ul class="list-group">
<li *ngFor="let data of projects" class="list-group-item">
<span class="event_release">{{data.startDate | date: 'dd/MM/yyyy'}} </span><br />
<strong>{{data.title}}</strong>
</li>
</ul>
year-filter.pipe.ts
export class YearFilterPipe implements PipeTransform {
transform(items: any[], args: any): any {
return items.filter(item => {
var startDate = new Date(item.startDate);
var endDate = new Date(item.endDate);
var realEndDate = new Date(item.realEndDate);
return ((startDate.getFullYear()===args.getFullYear());
});
}
}

In your Pipe use this:
#Pipe({ name: 'yearFilter', pure: false })
Your need to set properties pure to false. By default is true.

Related

Get into Firebase complex object containing another object

I've got Angular2 project connected directly with Firebase.
The structure of my database is presented in the picture below. So we've got couple of objects.
Main is orders, then the key od order, some extra information and another object "items" which contains several objects like 0, 1 etc. Each of them has a object called "product" which has some other parameters...
orders
-> datePlaced,
items
-> 0
-> quantity, totalPrice, product
->
imageUrl,
price,
title
My point is that when I'm creating "My Orders" tab, I'd like to get information of every item in specific order e.g. I see list of orders, and small button "View order", I click and I see details about this order with special key.
I prepared view with orders, buttons but I cannot take any objects form object orders, I've got a blank page.
order-details.component.ts
export class OrderDetailsComponent implements OnInit, OnDestroy {
order$;
userId: string;
userSubscription: Subscription;
constructor(private orderService: OrderService, private authService: AuthService) {}
async ngOnInit() {
this.userSubscription = this.authService.user$.subscribe(user => this.userId = user.uid);
this.order$ = this.authService.user$.switchMap(u => this.orderService.getOrdersByUser(u.uid));
}
ngOnDestroy() {
this.userSubscription.unsubscribe();
}
}
order-details.component.html
<div class="card" *ngIf="order$ | async as order">
<div class="card-body">
<h5 class="card-title">Your Order</h5>
<p class="card-text">You ordered {{ order.datePlaced | date }} items</p>
<ul class="list-group list-group-flush">
<li *ngFor="let order of order.shipping" class="list-group-item">
{{ order.city }} x {{ order.city }}
<div class="float-right">
{{ order.totalPrice | currency:'USD':'symbol' }}
</div>
</li>
<li class="list-group-item font-weight-bold">
Total
<div class="float-right">
{{ order.totalPrice | currency:'USD':'symbol' }}
</div>
</li>
</ul>
</div>
</div>
order.service.ts
export class OrderService {
constructor(private db: AngularFireDatabase, private shoppingCartService: ShoppingCartService) { }
async placeOrder(order) {
let result = await this.db.list('/orders').push(order);
this.shoppingCartService.clearCart();
return result;
}
getOrders() {
return this.db.list('/orders');
}
getOrdersByUser(userId: string) {
return this.db.list('/orders', {
query: {
orderByChild: 'userId',
equalTo: userId
}
});
}
}
How can I get every parameter from complex object "orders"?
I solved this by taking param routes in my order-details.component.ts and then a create function getOrder(id) in order service. When you have id of your order it's quite simple to take object from database.

Observable issue with async pipe

im using a library that help me to sort a list with drag-and-drop.
and the list that im giving it is an Observable of the list type, and then im using async to read it in the html, its very simple and looks like this:
#Injectable()
export class MyCmp implements OnInit {
myList: Observable<MyListType[]>;
showingList = false;
constructor(private _myService: MyService) {
};
public showListData(): void {
this.showingList = true;
this.myList = this._myService.getListData();
}
}
And this is the html:
<button md-button
(click)="showListData()"
title="">Show List
</button>
</div>
<md-content>
<div *ngIf="showingList">
<div dnd-sortable-container [sortableData]="myList | async">
<div class="list-bg" *ngFor="#item of myList | async; #i = index" dnd-sortable [sortableIndex]="i">
ID: {{item.id}} <p></p> Name: {{item.name}}
</div>
</div>
<div>Current List {{myList | async | json}}</div>
</div>
</md-content>
now this does not work, BUT, if I do this in my component instead of myList: Observable<MyListType[]>;
I do:
myList = this._myService.getListData();
and then in the html pass myList it works great...
I dont get it!! drive me crazy :/
please help
getListData() like like this:
public getListData(): Observable<MyListType[]> {
return this._someApiService.getCurrentListData().map(res => res.info);
}

how get the list of selected items in angular.js

Here I am using angular.js to show a list of people
<div class="recipient" ng-repeat="person in people">
<img src="{{person.img}}" /> person.name
<div class="email">person.email</div>
</div>
$scope.people = [{id:1}, {id:2}, {id:3}, {id:4}];
The looks is like below
What I want to do is I can select multiple items and by click a OK button, I can get a list of selected items. so If I select id 1 and id 2, then I want to get return a list of [{id:1},{id:2}]
How could I implement it in angular.js
Well I guess that if you're looping through a collection of people using a ng-repeat, you could add the ng-click directive on each item to toggle a property of you're object, let's say selected.
Then on the click on your OK button, you can filter all the people that have the selected property set to true.
Here's the code snippet of the implementation :
<div class="recipient" ng-repeat="person in people" ng-click="selectPeople(person)">
<img src="{{person.img}}" /> person.name
<div class="email">person.email</div>
</div>
<button ng-click="result()">OK</button>
function demo($scope) {
$scope.ui = {};
$scope.people = [{
name: 'Janis',
selected: false
}, {
name: 'Danyl',
selected: false
}, {
name: 'tymeJV',
selected: false
}];
$scope.selectPeople = function(people) {
people.selected = !people.selected;
};
$scope.result = function() {
$scope.ui.result = [];
angular.forEach($scope.people, function(value) {
if (value.selected) {
$scope.ui.result.push(value);
}
});
};
}
.recipient {
cursor: pointer;
}
.select {
color:green;
}
.recipient:hover {
background-color:blue;
}
<script src="https://code.angularjs.org/1.2.25/angular.js"></script>
<div ng-app ng-controller="demo">
<div class="recipient" ng-repeat="person in people" ng-click="selectPeople(person)" ng-class="{ select: person.selected }">
<div class="name">{{ person.name }}</div>
</div>
<button ng-click="result()">OK</button>
Result :
<ul>
<li ng-repeat="item in ui.result">{{ item.name }}</li>
</ul>
</div>
If you only want to show checked or unchecked you could just apply a filter, but you would need to toggle the filter value from undefined to true if you didn't wan't to get stuck not being able to show all again.
HTML:
<button ng-click="filterChecked()">Filter checked: {{ checked }}</button>
<div class="recipient" ng-repeat="person in people | filter:checked">
<input type='checkbox' ng-model="person.isChecked" />
<img ng-src="{{person.img}}" />{{ person.name }}
<div class="email">{{ person.email }}</div>
</div>
Controller:
// Apply a filter that shows either checked or all
$scope.filterChecked = function () {
// if set to true or false it will show checked or not checked
// you would need a reset filter button or something to get all again
$scope.checked = ($scope.checked) ? undefined : true;
}
If you want to get all that have been checked and submit as form data you could simply loop through the array:
Controller:
// Get a list of who is checked or not
$scope.getChecked = function () {
var peopleChkd = [];
for (var i = 0, l = $scope.people.length; i < l; i++) {
if ($scope.people[i].isChecked) {
peopleChkd.push(angular.copy($scope.people[i]));
// Remove the 'isChecked' so we don't have any DB conflicts
delete peopleChkd[i].isChecked;
}
}
// Do whatever with those checked
// while leaving the initial array alone
console.log('peopleChkd', peopleChkd);
};
Check out my fiddle here
Notice that person.isChecked is only added in the HTML.

How to perform an action when a filtered collection changes

I have 3 connected lists that need to work a bit like cascading dropdown lists, that is, selecting an item in the first list filters the second which filters the third.
To achieve this I am using angular filters like so:
<div ng-app="" ng-controller="DemoCtrl">
<h3>Categories</h3>
<ul>
<li ng-repeat="cat in model.categories"
ng-click="selectCategory(cat)"
ng-class="{ active: cat === selectedCategory }">{{ cat }}</li>
</ul>
<h3>Sub Categories</h3>
<ul>
<li
ng-repeat="cat in model.subCategories | filter: { parent:selectedCategory }"
ng-click="selectSubCategory(cat)"
ng-class="{ active: cat.name === selectedSubCategory }">{{ cat.name }}</li>
</ul>
<h3>Products</h3>
<ul>
<li ng-repeat="product in model.products | filter:{ category:selectedSubCategory }">{{ product.name }}</li>
</ul>
</div>
When the top level category changes (selectCategory) I need to ensure that the first sub category is also selected:
$scope.selectCategory = function (cat) {
$scope.selectedCategory = cat;
// how to select the first sub category?
};
Since setting $scope.selectedCategory updates the filtered sub categories, is there anyway I can be notified when the filtered collection changes so I can select the first item ($scope.selectSubCategory)?
http://jsfiddle.net/benfosterdev/dWqhV/
You could set up a watcher on $scope.selectedCategory and manually run $filter to get the first sub-category.
In the end I opted for just performing the filtering in my controller and binding to a "filtered" object on my $scope. When the primary category changed we re-filter the subcategories and select the first item:
$scope.selectCategory = function (cat) {
$scope.model.selectedCategory = cat;
var filtered = $scope.getSubCategoriesOf(cat);
$scope.model.filteredSubCategories = filtered;
$scope.selectSubCategory(filtered[0]);
}
$scope.getSubCategoriesOf = function (cat) {
return $filter('filter')($scope.model.subCategories, { parent: cat }, true);
}

Angularjs directive to append to template

I am new to angularjs world and am trying to do something that I think should be achievable with a directive.
I have a template which has a list of articles listed using ng-repeat. These articles have a date on them. I want to group the articles by date in the template. So I am thinking of creating a directive that would append a new div before each group of articles in that day. The data in the model is already sorted by date desc.
Should I be using the compile function in the directive to do this ? Any code examples would be great.
If I understand you correctly you want the output to be something like:
<ul>
<li>
Show 3 articles for date 2012-12-07
</li>
<li>
Show 1 articles for date 2012-12-06
</li>
<li>
Show 2 articles for date 2012-12-05
</li>
</ul>
In that case, I would do the grouping before it renders:
function ArticlesController ($scope) {
var groupArticles = function (articles) {
var i,
art = {};
for (i = 0; i < articles.length; i += 1) {
if (!art.hasOwnProperty(articles[i].date)) {
art[articles[i].date] = [];
}
art[articles[i].date].push(articles[i]);
}
return art;
};
$scope.articles = [{ date: '2012-12-07', title: 'Marcus' },
{ date: '2012-12-07', title: 'Zero' },
{ date: '2012-12-06', title: 'Moxxi' },
{ date: '2012-12-05', title: 'Dr Zed' }];
$scope.groupedArticles = groupArticles($scope.articles);
}
And you view:
<ul data-ng-controller="ArticlesController">
<li data-ng-repeat="articles in groupedArticles">
<div data-ng-repeat="article in articles">
{{ articles.title }}
</div>
</li>
</ul>
<ul>
<li ng-repeat="article in articles">
<ng-switch on="$first || article.date != articles[$index-1].date">
<div ng-switch-when="true" class="group_heading">{{article.date}}</div>
</ng-switch>
{{article.title}}
</li>
</ul>
The above is modeled off an existing fiddle I had.
The above assumes (as you stated) that articles is already sorted. If not, the fiddle shows how to use the orderByFilter in a controller to create a sorted array based on any object property.

Resources