0

I have a service that returns a list of pages. Now I want to write a pipe named pagesFilter that returns a list of pages that has this key set as true.

Then I want to apply this filter when clicking on a navigation item.

Somehow I can't get it to work. There are no errors in the console, and the filter variable gets updated correctly. Any advice is appreciated.

My html:

<!-- portfolio submenu -->
<div id="portfolioMenu">
    <div id="portfolioMenuOrangeLine"></div>
    <div id="filter1" class="miniNavButton" (click)="changeFilter('app demos')">
        <a>
            <svg class="icon icon-eye">
                    <use xlink:href="symbol-defs.svg#icon-eye"></use>
                </svg>
        </a>
    </div>
    <div id="filter2" class="miniNavButton" (click)="changeFilter('github repos')">
        <a>
            <svg class="icon icon-embed">
                    <use xlink:href="symbol-defs.svg#icon-embed"></use>
                </svg>
        </a>
    </div>
    <div id="filter3" class="miniNavButton" (click)="changeFilter('work in progress')">
        <a>
            <svg class="icon icon-hammer">
                    <use xlink:href="symbol-defs.svg#icon-hammer"></use>
                </svg>
        </a>
    </div>
</div>

<h2 class="filterHeading">Showing: {{ filter }}</h2>

<!-- portfolio content -->
<div class="portfolioContainer">
    <div class="displayHack"></div>
    <div *ngFor="#p of pages" class="portfolioPageContainer">
        <img [attr.src]="p.img" class="portfolioThumbnail">
        <h2>{{ p.name }}</h2>
        <a [attr.href]="p.repo">
            <div>
                <p>{{ p.description }}</p>
            </div>
            <p class="portfolioRepoLink">See the Code!</p>
        </a>
    </div>
    <div class="displayHack"></div>
</div>

pages service:

import { Injectable } from 'angular2/core';

export class Page {
    constructor(public img: string, public name: string, public repo: string, public description: string, public demo: boolean, public github: boolean, public finished: boolean) { }
}

@Injectable()
export class PagesService {
    getPages() {
        return [
            new Page('./app/images/placeholder.png', 'veryNiceWords', 'https://github.com/Shooshte/veryNiceWords', 'A hobby app, made to enable posting, rating and sharing quotes over social networks. Work in progress.', false, true, false),
            new Page('./app/images/placeholder.png', 'ZIC IJS', 'https://github.com/Shooshte/ZIC', 'Refurbishing of on old library webpage with AngularJS.', false, true, false),
            new Page('./app/images/weather.png', 'Show the Local weather', 'http://codepen.io/shooshte/pen/NxOwOX', 'A freeCodeCamp exercise, designed to show the local weather.', true, false, true),
            new Page('./app/images/calculator.png', 'Calculator', 'http://codepen.io/shooshte/pen/qbjJdy', 'A freeCodeCamp exercise, which requires you to build a javascript calculator.', true, false, true),
            new Page('./app/images/github.png', 'MTGO Draft Replayer', 'https://github.com/Shooshte/MTGO-Draft-Replayer', 'A simple web app that opens a MTGO draft log file, and re-creates the draft from it.', false, true, false),
            new Page('./app/images/codeeval.png', 'codeEval', 'https://github.com/Shooshte/CodeEval', 'CodeEval challenges solutions written in javascript and posted to gitHub.', false, true, true)
        ];
    }
}

portfolio component (that uses the service):

import { Component } from 'angular2/core';
import { ViewEncapsulation } from 'angular2/core';
import { Page, PagesService } from './pages.service';
import { Pipe, PipeTransform } from 'angular2/core';

@Pipe({ name: 'filter' })
export class pagesFilter {
    transform(pages, [key]): string {
        return pages.filter(page => {
            return page.hasOwnProperty(key);
        });
    }
}

@Component({
    selector: 'portfolio',
    templateUrl: '/app/views/portfolio.html',
    styleUrls: ['../app/styles/PortfolioMobile.css', '../app/styles/PortfolioOther.css'],
    pipes: [pagesFilter],
    encapsulation: ViewEncapsulation.None
})

export class PortfolioComponent {
    filter = 'everything';

    filterPortfolio(parameter:String) {
        return this.pages ? 'pagesFilter' : parameter
    }

    changeFilter(x) {
        this.filter = x;

        if (x == 'app demos') {
            this.filterPortfolio('demo');
        }
        else if (x == 'github repos') {
            this.filterPortfolio('repo');
        }
        else if (x == 'miniNavButton') {
            this.filterPortfolio('finished');
        }
    }

    pages: Page[];

    constructor(private _pagesService: PagesService) { }

    ngOnInit() {
        this.pages = this._pagesService.getPages();
    }

}
3
  • I coudn't find the usage of pagesFilter, it is supposed to be in porfolio.html where is it ? It should look like what Thierry described in the answer. Commented Apr 20, 2016 at 13:00
  • the changeFilter() function calls this.FilterPortfolio, which calls pagesFilter Commented Apr 20, 2016 at 13:02
  • return this.pages ? 'pagesFilter' : parameter doesn't make a call to pagesFilter , it's just a string, moreover pagesFilter is not a function, it's a pipe supposed to be used in template just like Thierry's answer. Commented Apr 20, 2016 at 13:09

3 Answers 3

1

You need to provide a parameter to the pipe:

@Pipe ({
  name:'filter'
})
export class FilterPipe {
  transform(value, params) {
    var filter = params[0];

    return value.filter((item)=> {
      // for example
      return (item.name === filter);
    });
  }
}

You can use this pipe this way basing on a form input and a component property:

@Component({
  (...)
  template: `
    <form>
      <input [ngFormControl]="ctrl"/>
    </form>

    <div *ngFor="#elt of elements | filter:filterValue">{{elt.name}}</div>
  `,
  pipes: [ FilterPipe ]
})
export class MyComponent {
  filterValue:string;
  ctrl:Control;

  contructor() {
    this.control = new Control();
    this.control.values.debounceTime(500).subscribe(
      (data) => {
        this.filterValue = data;
      }
    );
  }
}

Edit

You could also update filterValue on click events:

@Component({
  (...)
  template: `
    <div (click)="updateFieldValue('new value')">
      Update
    </div>

    <div *ngFor="#elt of elements | filter:filterValue">{{elt.name}}</div>
  `,
  pipes: [ FilterPipe ]
})
export class MyComponent {
  filterValue:string;

  updateFilterValue(newValue) {
    this.filterValue = newValue;
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

the problem with this is that I want to control the filter using navigation buttons - plain old divs. So I don't actually use tha filter anywhere in my html.
You could update the filterValue from click handlers ;-) I updated my answer accordingly...
1

Before using the Pipe inside a component you need to add it inside pipe option of that component MetaData.

@Component({
    selector: 'portfolio',
    templateUrl: '/app/views/portfolio.html',
    styleUrls: ['../app/styles/PortfolioMobile.css', '../app/styles/PortfolioOther.css'],
    pipes: [pagesFilter], //add pipe here
    encapsulation: ViewEncapsulation.None
})

2 Comments

added pipes: [pagesFilter], still not working properly though. Also why is there no error when I call the function that uses the filter if the filter was not present in the component?
updated main question with this since I still can't get the filter to work. Thanks for the input
0

I was facing the same issue. Pipe was perfect no errors in console. I resolved it by stopping current ng serve and re-running it. The issue is, when ever you add a pipe, It is also added to modules. ng serve mostly doesn't detect changes in modules. So you have to re-run ng serve. Might be helpful.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.