NGRX 5 piped selector - ngrx

In this article on medium.com (13 Feb.) regarding NGRX 5 they present pipeable selectors. This reminds me on reading about pipeable selectors in rxjs where they could not just be justified by 'its pure function, bro', but also by the way functions could be declared and reused in different occurences without using map every time to then call a letable function.
So i can agree, that this is a good thing in rxjs, but why would we need this in ngrx - for selectors. The linked article shows the following example:
import { Store, select } from '#ngrx/store';
import { Observable } from 'rxjs/Observable';
interface AppState {
count: number;
}
#Component({
selector: 'my-app',
template: `
<button (click)="increment()">Increment</button>
<div>Current Count: {{ count$ | async }}</div>
<button (click)="decrement()">Decrement</button>
<button (click)="reset()">Reset Counter</button>
`
})
export class MyAppComponent {
count$: Observable<number>;
constructor(private store: Store<AppState>) {
this.count$ = store.pipe(select('count'));
}
}
So we now call store.pipe(select(...));
instead of store.select(Selector); - where are the gains? why should i change my code to use this behaviour or at least start to use pipeable selectors?

In NgRx 7 this deprecation is been reverted - see changelog.

Related

How to use react-jss within react class Components?

In react-jss documentation, the authors have written:
'HOC based API is deprecated as of v10 and will be removed in v11.'
This means, as far as I understand, that such HOC functionality as injectSheet and withStyles will no longer be available in V11.
The new react-based stylesheet generating functions seem to be all based on react hooks. The function createUseStyles seemed very promising to myself and my team, until upon looking further into the source code we realised that it was only available within functional components, as it makes use of hooks.
The Problem
As a team we still make heavy use of React Class components and have no plans to move completely to hooks, not because hooks aren't useful, but because sometimes functional components aren't the best or most organised solution to writing a component.
Perhaps I'm missing something-- but it seems like there is now no solution left for React Class based components, other than writing our own manual implementation from core jss.
What solutions are there for a developer to make use of react-jss in a way similar to that achieved by createUseStyles, keeping up with the latest version of react-jss, being able to pass dynamic props, and etc. without writing a manual implementation?
While not specific to JSS, keep in mind that you can always use a tiny wrapper to convert any Hook to render prop or a HOC.
Converting Hook to a render prop is described here: https://reacttraining.com/blog/using-hooks-in-classes/
You can use a similar approach to convert any Hook to a HOC.
import { Classes } from 'jss';
import { createUseStyles } from 'react-jss';
First, lets create a more type safe function for creating styles.
export function createStyles(classes: { [name: string]: Partial<CSSStyleDeclaration> }) {
return createUseStyles(classes as any);
}
Secondly, we'll create a simple wrapper to allow hooks for our components.
function Styles<T extends string | number | symbol>(props: { styles: () => Classes<T>, children: (classes: Classes<T>) => ReactElement }) {
const classes = props.styles();
return props.children(classes);
}
Example
const styles = createStyles({
title: {
fontSize: '25px',
textTransform: 'uppercase'
},
message: {
color: 'red'
}
});
export const App = () => (
<Styles styles={styles}>
{classes => (
<Fragment>
<h1 className={classes.title}>Title</h1>
<p className={classes.message}>message</p>
</Fragment>
)}
</Styles>
);
Output

Clarity Datagrid Custom filter example

Does anyone have a complete example of a custom filter for the clarity datagrid? The custom filter documentation is lacking and I can't figure out how to get their example to work. Better yet, a stackblitz for the full datagrid demo would be amazing!
Hope this helps:
1) My Field model field.ts
export interface Field {
field_nbr: number;
fieldType: string;
dataType: string;
}
2) Utility file util-filters.ts -
import {ClrDatagridStringFilterInterface} from "#clr/angular";
//Models
import { Field } from '../models/field';
/**
* Class for filtering Field metadata in datagrids on filterType property of model
*/
export class FieldTypeFilter implements ClrDatagridStringFilterInterface<Field> {
accepts(field: Field, search: string):boolean {
return "" + field.fieldType == search
|| field.fieldType.toLowerCase().indexOf(search) >= 0;
}
}
3) model-component.html
<clr-datagrid [(clrDgSingleSelected)]="singleSelected" [clDgRowSelection]="false">
<clr-dg-column >
Field Type
<clr-dg-string-filter [clrDgStringFilter]="fieldTypeFilter"></clr-dg-string-filter>
</clr-dg-column>
<clr-dg-column ><ng-container *clrDgHideableColumn="{hidden: false}">Data Type</ng-container></clr-dg-column>
<clr-dg-placeholder>No matching fields found</clr-dg-placeholder>
<clr-dg-row *clrDgItems="let field of allFields" [clrDgItem]="field" (click)='openModal(field)'>
<clr-dg-cell>{{field.fieldType}}</clr-dg-cell>
<clr-dg-cell>{{field.dataType}}</clr-dg-cell>
</clr-dg-row>
</clr-datagrid>
4) model-component.ts
import { Component, OnInit, ViewChild } from '#angular/core';
import { NgIf } from '#angular/common';
import { Wizard } from "#clr/angular";
import { Observable } from 'rxjs';
//Models
import { Field } from '../models/field';
//Utilities
import { FieldTypeFilter } from "../utils/field-filters";
#Component({
selector: 'model',
templateUrl: './model.component.html',
providers: [],
styleUrls: ['../app.component.css']
})
export class ModelComponent {
private fieldTypeFilter = new FieldTypeFilter;
....
}
Edit 01/14/2022
Sorry, I moved some things around on stackblitz and we have updated the repo since this was written.
Here is where the custom filter lives for the demo: https://github.com/vmware/clarity/blob/angular/src/app/datagrid/utils/color-filter.ts
I'm not posting source code because there are 12 different files and some are pretty long (> 100 loc).
Here is a working reproduction of the full demo in the Clarity docs: https://stackblitz.com/edit/full-datagrid-demo
If you ever have questions about how a Clarity component works you can always dive into the source code for the demos we use for development and testing. Take a look here, I linked to the dev app we use for dev/testing so you know where I got the full datagrid code from. https://github.com/vmware/clarity/tree/master/src/dev/src/app

Firebase angularfire2 get object from database

I have a problem using an object i get from my firebase db.
I can recieve the json file without any problems as you can see on the picture below.
https://i.gyazo.com/6c1c69aca47f92a4e1029bb019042ab2.png
<h1>{{ item | async | json}}</h1>
the above code is in /src/app/app.component.html ,
this recieves the item object from /src/app/app.component.ts
import { Component } from '#angular/core';
import { AngularFire, FirebaseObjectObservable } from 'angularfire2';
#Component({
moduleId: module.id,
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
})
export class AppComponent {
item: FirebaseObjectObservable<any>;
constructor(af: AngularFire) {
this.item = af.database.object('/releases/');
}
}
I also have tried using item.name.$value but it doesn't work. I would want to get the values in the json file. And be able to use them in the website.
First you don't need the beginning and ending slash when searching for the object, this will work:
af.database.object('releases')
Next, you don't need the json pipe because firebase objects are already in json notation. Your html can look like this:
<h1>{{ item | async }}</h1>
Typically, however, instead of using your firebase async object directly on your template, you would pass it into a presentation component (also known as a dumb component). The presentation component doesn't need to know anything about the asynchronous behavior of your object, it just needs to handle how to generate the html. This is a common pattern when dealing with async objects in your template.
So your html would become:
<my-child-component [item]="item | async">
The child component:
#Component({
selector: 'my-child-component',
template: '<h1>{{ item }}</h1>'
})
export class MyChildComponent {
#Input() item: any;
...
as described here
https://github.com/angular/angularfire2/blob/master/docs/2-retrieving-data-as-objects.md#retrieve-data
try:
<h1>{{ (item | async)?.gore}}</h1>

Moment.js with Vuejs

I try to print out date time using like the following in vue-for
{{ moment().format('MMMM Do YYYY, h:mm:ss a') }}
but, it does not appear. It's just a blank. How I can try to use moment in vue?
With your code, the vue.js is trying to access the moment() method from its scope.
Hence you should use a method like this:
methods: {
moment: function () {
return moment();
}
},
If you want to pass a date to the moment.js, I suggest to use filters:
filters: {
moment: function (date) {
return moment(date).format('MMMM Do YYYY, h:mm:ss a');
}
}
<span>{{ date | moment }}</span>
[demo]
If your project is a single page application, (eg project created by vue init webpack myproject),
I found this way is most intuitive and simple:
In main.js
import moment from 'moment'
Vue.prototype.moment = moment
Then in your template, simply use
<span>{{moment(date).format('YYYY-MM-DD')}}</span>
In your package.json in the "dependencies" section add moment:
"dependencies": {
"moment": "^2.15.2",
...
}
In the component where you would like to use moment, import it:
<script>
import moment from 'moment'
...
And in the same component add a computed property:
computed: {
timestamp: function () {
return moment(this.<model>.attributes['created-at']).format('YYYY-MM-DD [at] hh:mm')
}
}
And then in the template of this component:
<p>{{ timestamp }}</p>
I made it work with Vue 2.0 in single file component.
npm install moment in folder where you have vue installed
<template>
<div v-for="meta in order.meta">
{{ getHumanDate(meta.value.date) }}
</div>
</template>
<script>
import moment from 'moment';
export default {
methods: {
getHumanDate : function (date) {
return moment(date, 'YYYY-MM-DD').format('DD/MM/YYYY');
}
}
}
</script>
Here is an example using a 3rd party wrapper library for Vue called vue-moment.
In addition to binding Moment instance into Vue's root scope, this library includes moment and duration filters.
This example includes localization and is using ES6 module imports, an official standard, instead of NodeJS's CommonJS module system requires.
import Vue from 'vue';
import moment from 'moment';
import VueMoment from 'vue-moment';
// Load Locales ('en' comes loaded by default)
require('moment/locale/es');
// Choose Locale
moment.locale('es');
Vue.use(VueMoment, { moment });
Now you can use the Moment instance directly in your Vue templates without any additional markup:
<small>Copyright {{ $moment().year() }}</small>
Or the filters:
<span>{{ 3600000 | duration('humanize') }}</span>
<!-- "an hour" -->
<span>{{ [2, 'years'] | duration('add', 1, 'year') | duration('humanize') }}</span>
<!-- "3 years" -->
// plugins/moment.js
import moment from 'moment';
moment.locale('ru');
export default function install (Vue) {
Object.defineProperties(Vue.prototype, {
$moment: {
get () {
return moment;
}
}
})
}
// main.js
import moment from './plugins/moment.js';
Vue.use(moment);
// use this.$moment in your components
For moment.js at Vue 3
npm install moment --save
Then in any component
import moment from 'moment'
...
export default {
created: function () {
this.moment = moment;
},
...
<div class="comment-line">
{{moment(new Date()).format('DD.MM.YYYY [ ] HH:mm')}}
</div>
Moment.js with Vue3 js
npm install moment --save # npm
yarn add moment # yarn
Main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import moment from 'moment'
const app = createApp(App)
app.config.globalProperties.$moment = moment
app.use(router).mount('#app')
Used moments in vue3 js component
{{ $moment(item.created_at).format("YYYY-MM-DD") }} // 2021-07-03
global members are not available by default in your <template>'s scope. But you can easily pass them on using computed properties.
computed: {
moment: () => moment,
console: () => console,
window: () => window
}
Now you can use any of them in your template. i.e: console.log(moment(), window).
Note this doesn't add any overhead.
vue-moment
very nice plugin for vue project and works very smoothly with the components and existing code.
Enjoy the moments...😍
// in your main.js
Vue.use(require('vue-moment'));
// and use in component
{{'2019-10-03 14:02:22' | moment("calendar")}}
// or like this
{{created_at | moment("calendar")}}
I've read the solutions posted here and it seems to be more complex than my solution so I'm presenting this one, what I do is like this
The thing you need:
import moment from 'moment';
...
data() {
return {
moment: moment, // This is the one line of code that you need
}
}
So this is what it looks like
HTML (Now this works):
<h1>{{moment().format('MMMM Do YYYY, h:mm:ss a')}}</h1>
JS:
import moment from 'moment';
export default {
data() {
return {
moment: moment, // This is the one line of code that you need
}
}
}
I'd simply import the moment module, then use a computed function to handle my moment() logic and return a value that's referenced in the template.
While I have not used this and thus can not speak on it's effectiveness, I did find https://github.com/brockpetrie/vue-moment for an alternate consideration
TESTED
import Vue from 'vue'
Vue.filter('formatYear', (value) => {
if (!value) return ''
return moment(value).format('YYYY')
})
Install the moment module:
npm i moment
In your vue component:
import moment from 'moment';
export default {
data(){
},
methods:{
moment(date){ return moment(date) }
}
}
Inside the template:
<span>{{ moment().format('MMMM Do YYYY, h:mm:ss a') }}</span>

Angular 2: How to call the method on a nested component?

I'm trying to call functions on an element declared in my Angular 2 component.
The issue is that I don't know how to retrieve the element from my JS code.
If I can pass the element from the template to the JS code, it works, but
using document.querySelector does not return anything.
Example code (plunk):
#View({
template: `
<div>
<span id="p1">{{name}}</span>
<span #p2>{{name}}</span>
</div>
`,
encapsulation: ViewEncapsulation.Native
})
export class Person {
sayHello(e) {
p1 = document.querySelector('p1');
console.log('p1:', p1)
p2 = document.querySelector('p2');
console.log('p2:', p2)
alert('VanillaId: ' + (p1 ? p1.innerHTML : 'null') +
'\nAngularId: ' + (p2 ? p2.innerHTML : 'null'));
}
}
I suspect that it has something to do with shadow dom, but I don't know how to
get the shadow root and use it to do the query. this doesn't seem to expose
anything useful to access the dom.
Use ElementRef see it here http://plnkr.co/edit/LISYnq?p=preview
I did play around with your plunker:
I don't know how to retrieve the element from my JS code
It strikes me you might be able to just setup your component state in your js code and then mutate/display it usingg property binding, and communicate in/out with events.
If you provide a more specific use case maybe we can offer more advice. Anyway, heres the code:
person.ts
//a simple person component
import {Component, View, ViewEncapsulation, Input, ElementRef} from 'angular2/angular2'
#Component({
selector: 'my-person',
inputs: ['name'],
template: `
<pre>
<span> (Unsuspecting shadow dom node minding its own business)</span>
<span #p0el> Name : {{name}}</span>
<span #p1el> Passed in : {{p1}}</span>
</pre>
`,
encapsulation: ViewEncapsulation.Native
})
export class Person {
public p1:string = "...";
#Input('name') name:string;
constructor (elementRef: ElementRef) {
this.elementRef = elementRef;
}
sayHello(str) {
this.p1 = str;
this.elementRef.nativeElement.shadowRoot.querySelector('span').textContent = "BAM!"
}
}
app.ts
//our root app component
import {Component, View, CORE_DIRECTIVES, ViewEncapsulation} from 'angular2/angular2'
import {Person} from './person'
#Component({
selector: 'my-app',
template: `
<div>
<!-- Passing the element here works fine -->
<button (click)="person.sayHello('Clicked!') && person.name = 'Clicky name'">Test</button>
<my-person #person [name]="'World'"></my-person>
</div>`,
directives: [CORE_DIRECTIVES, Person],
encapsulation: ViewEncapsulation.Native
})
export class App {
test(personComponent: Person) {
}
}

Resources