How to set condition in ngstyle or ngclass - ng-class

I have 2 different pages which is going to display the same data and both are sharing the same components. But both pages has different resolution one is the size with the alert box and one is similarly A4 size. how to set dynamic height and width for them. I tried using ngstyle not sure how to implement it correctly
in normal html
<tbody class="classname" style="height: 60px; width: fit-content;">
i added this and it works but both pages taking the same resolution.
so with ngstyle i tried this again same thing both pages has been set to same 60
[ngStyle]="{'height.px': 'Height' ? '60' : '200' }"
or it there any solution using ngclass?

So your problem breaks-down in two steps. One is to calculate the page height which is not an angular field and rather browser-specific issue. Although browsers do expose clientHeight or scrollHeight properties but there is a difference on how different browsers understand the actual height of the page.
So the best practice (as its also used by famous jQuery library) is to get the different document-level height properties and get the maximum value out of those.
You'll have to inject the DOCUMENT constant to access the DOM document into your component. Please find the below example angular component code.
import { Component, OnInit, Inject } from '#angular/core';
import { DOCUMENT } from '#angular/common';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
public height = 0;
constructor(#Inject(DOCUMENT) private document: any){
}
ngOnInit() {
this.height = Math.max( this.document.body.scrollHeight, this.document.body.offsetHeight,
this.document.documentElement.clientHeight, this.document.documentElement.scrollHeight, this.document.documentElement.offsetHeight );
}
}
Now simply on the html side you could test the height property of component and apply the style as desired. Somethink like this..
<div [ngStyle]="{'height': height>=200 ? '200px' : '60px' }"></div>
Thanks.

Related

How to change the height of d3 observable notebook embed

so I understand that I can change the fixed width instead of a responsive width, by importing Library, then re-assigning the width value. But I also want to change the height and including ,height: 500 doesn't seem to work. What am I doing wrong and what other way is there to embed the d3 observable notebook chart with customizable width and height without using an iframe?
<div class="chart"></div>
<p>Credit: <a href="https://observablehq.com/#tripletk/mmcovid19-confirmedcases">Myanmar COVID-19 Total Lab
Confirmed Cases by Timmy Kyaw</a></p>
<script type="module">
import {
Runtime,
Inspector,
Library
} from "https://cdn.jsdelivr.net/npm/#observablehq/runtime#4/dist/runtime.js";
const runtime = new Runtime(Object.assign(new Library, {
width: 500
}));
import define from "https://api.observablehq.com/d/1adf72a9a09835c3.js?v=3";
const main = runtime.module(define, name => {
if (name === "chart") return Inspector.into(".chart")();
});
</script>
Width works differently than height in Observable notebooks. You’ve already found how to change width: it’s a reactive variable that you can override with a constant like you’re doing; by default it uses with width of the document body.
For height, or any other value you want to inject like data or zipCode, you should use main.redefine("height", 500). (I’m using 200 in the example below, just change it to 500.)
<div class="chart"></div>
<p>Credit: <a href="https://observablehq.com/#tripletk/mmcovid19-confirmedcases">
Myanmar COVID-19 Total Lab Confirmed Cases by Timmy Kyaw</a></p>
<script type="module">
import {
Runtime,
Inspector,
Library
} from "https://cdn.jsdelivr.net/npm/#observablehq/runtime#4/dist/runtime.js";
const runtime = new Runtime(Object.assign(new Library, {
width: 500
}));
import define from "https://api.observablehq.com/d/1adf72a9a09835c3.js?v=3";
const main = runtime.module(define, name => {
if (name === "chart") return Inspector.into(".chart")();
});
main.redefine("height", 200)
</script>
Often it’s useful to make the figure fill an enclosing div instead of hardcoding a width and height: see this example of that approach. Also for reference, the docs have more information about both the redefine and new Library techniques.

Angular Animation: Page transition without style `position: absolute`?

Purpose: I want to add a nice transition effect when click from one page to another
I tried lots of solution online, including:
Angular 2 — Animating Router transitions
Page transition animations with Angular 2.0 router and component interface promises
....
one thing in common is that they all have style like position: absolute or position: fixed added, which breaks my existing app layout.
I remember when I using Angular 1, there's no need to add position: absolute to <div ui-view><div>
Is it possible in Angular 2 or 4?
You can add the absolute positioning exclusively to the leaving animation.
transition(':enter', [
style({transform: 'translateX(100%)'}),
animate('0.3s ease-in-out', style({transform: 'translateX(0%)'}))
]),
transition(':leave', [
style({transform: 'translateX(0%)', position: 'absolute', left: 0, right: 0, top: 0}),
animate('0.3s ease-in-out', style({transform: 'translateX(-100%)'}))
])
So only the leaving route is positioned absolutely, while the entering route is positioned staticly.
If it doesn't work, make sure that your router-outlet is wrapped by position: relative
<div style="position: relative;">
<router-outlet></router-outlet>
</div>
And that your route-components have display: block
#Component({
styles:[':host {display: block;}']
Talking about Angular version 4.3.x. Reading the router documentation, they explain how to add animation between routes. Here is a resume for the lazy ones (including myself).
You want to import animations libraries from #angular/core (and not #angular/animations):
import {
AnimationEntryMetadata,
animate,
state,
style,
trigger
} from '#angular/core';
export const fadeInAnimation: AnimationEntryMetadata = trigger('fadeInAnimation', [
transition(':enter', [
style({
opacity: 0,
transform: 'translateY(20px)'
}),
animate(
'.3s',
style({
opacity: 1,
transform: 'translateY(0)'
})
)
])
]);
Then in your component, use the HostBinding decorator in order to specify the component's layout css properties (you don't need use a fixed or absolute position):
import { Component, OnInit, HostBinding } from '#angular/core';
import { fadeInAnimation } from './../animations/fadein';
#Component({
animations: [fadeInAnimation],
selector: 'app-posts',
templateUrl: './posts.component.html'
})
export class DemandsComponent implements OnInit {
#HostBinding('#fadeInAnimation') fadeInAnimation = true;
#HostBinding('style.display') display = 'block';
#HostBinding('style.position') position = 'relative';
// Rest of the code
}
Adding this to each routed component can be cumbersome. The documentation suggest, and I quote:
Applying route animations to individual components works for a simple demo, but in a real life app, it is better to animate routes based on route paths.
This article from Matias Niemelä can help https://www.yearofmoo.com/2017/06/new-wave-of-animation-features.html#routable-animations

How to get the initial device orientation in NativeScript with Angular 2

I am getting started with NativeScript + Angular 2 and I'd like to implement a component that activates different routes depending on the device orientation. After much search, I was able to get this working but I haven't yet figured out how to get the initial device orientation, which sounds like it should be easier.
Here's my AppComponent code. Look at ngAfterViewInit:
import {Component, OnInit, OnDestroy, AfterViewInit} from "#angular/core";
import {Router} from "#angular/router";
import _application = require('application');
#Component({
selector: "my-app",
templateUrl: "app.component.html",
})
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
constructor(private router: Router) {}
ngOnInit() {
_application.on(_application.orientationChangedEvent, this.setOrientation.bind(this));
}
ngAfterViewInit() {
// How do I get the initial orientation here instead of hardcoding to 'portrait'?
this.setOrientation({newValue: 'portrait'})
}
ngOnDestroy() {
_application.off(_application.orientationChangedEvent, this.setOrientation);
}
setOrientation(args) {
if (args.newValue === 'landscape') {
this.router.navigate(['/landscape']);
} else {
this.router.navigate(['/portrait']);
}
}
}
private activity:any = application.android.foregroundActivity;
this.activity.getResources().getConfiguration().orientation;
You could use this plugin. In order to get access to the up-to-date version, you will need to pay a monthly subscription to the developers that maintain ProPlugins.
You can installed the last free version of it using:
npm i nativescript-orientation
This comes with no guaranties that it will work, especially in {N} 6+.
Once installed, you can get the current screen orientation like this:
const orientation = require("nativescript-orientation");
console.log(orientation.getOrientation());
While there is no helper to determine the initial orientation that I know of, you can still get the current screen dimensions. You may import the screen module from the core library.
import { screen } from 'tns-core-modules/platform';
Then on application initialization determine the orientation by determining if the screen height is larger than the width:
this.orientation = screen.mainScreen.heightPixels > screen.mainScreen.widthPixels ? 'portrait' : 'landscape';
Edit: This may be inconsistent and is not fully tested (meaning the screen height might not always be the height of the screen in portrait mode). If this is the case, on page load, you may use the same strategy to measure the main Page element and compare the height and width of the view to determine orientation.

Angular2 SVG filter url

I'm using Angular2 + D3 to create a chart.
I'd like to apply an svg filter to the bars in order to create a drop-shadow effect.
While the filter is created and the bars have a filter: url("#dropshadow") style applied, the shadow does not render.
Could this be due to Angulars single page and the url() not finding the filter? What would be the correct way to work around this issue?
I finally figured it out. The best solution seems to be to inject the Location via
import { Location } from '#angular/common';
...
constructor(private location: Location)
and then use it to specify the path for the url()
.style('filter', 'url(' + this.location.path() + '#drop-shadow)')
Now it works as expected.
In case some one arrives here and this isn't clear enough here is what i did for any url used in <svg> with Safari:
In my components i import Location
import { Location } from '#angular/common';
...
constructor(private location: Location) {
}
url(id: string) {
return `url(${this.location.path()}${id}`;
}
}
Then use it in the inline <svg> tags as follows
[attr.filter]="url('#filter-11')"
[attr.clip-path]="url('#clip')"

Animated page transitions in react

The past couple of weeks I've been working on an app using React. So far everything is working fine, but now I want to add some transitions to it. These transitions are a bit more complex than any examples I managed to find.
I've got 2 pages, an overview and a detail page which I'd like to transition between.
I'm using react-router to manage my routes:
<Route path='/' component={CoreLayout}>
<Route path=':pageSlug' component={Overview} />
<Route path=':pageSlug/:detailSlug' component={DetailView} />
</Route>
Overview looks like this:
Detailview looks like this:
The idea of the transition is that you click on one of the elements of the Overview. This element which has been clicked moves towards the position it should have on the detailView. The transition should be initiated by a route change (I think) and should also be able to happen in reverse.
I've already tried using ReactTransitionGroup on the Layout, which has a render method which looks like this:
render () {
return (
<div className='layout'>
<ReactTransitionGroup>
React.cloneElement(this.props.children, { key: this.props.location.pathname })
</ReactTransitionGroup>
</div>
)
}
This will give the child component the ability to receive the special lifecycle hooks. But I'd like to access the child components somehow during these hooks and still keep doing things the React way.
Could someone point me in the right direction for the next step to take? Or maybe point me to an example which I may have missed somewhere? In previous projects I used Ember together with liquid fire to get these kinds of transitions, is there maybe something like this for React?
I'm using react/react-redux/react-router/react-router-redux.
Edit: Added a working example
https://lab.award.is/react-shared-element-transition-example/
(Some issues in Safari for macOS for me)
The idea is to have the elements to be animated wrapped in a container that stores its positions when mounted. I created a simple React Component called SharedElement that does exactly this.
So step by step for your example (Overview view and Detailview):
The Overview view gets mounted. Each item (the squares) inside the Overview is wrapped in the SharedElement with a unique ID (for example item-0, item-1 etc). The SharedElement component stores the position for each item in a static Store variable (by the ID you gave them).
You navigate to the Detailview. The Detailview is wrapped into another SharedElement that has the same ID as the item you clicked on, so for example item-4.
Now this time, the SharedElement sees that an item with the same ID is already registered in its store. It will clone the new element, apply the old elements position to it (the one from the Detailview) and animates to the new position (I did it using GSAP). When the animation has completed, it overwrites the new position for the item in the store.
Using this technique, it's actually independent from React Router (no special lifecycle methods but componentDidMount) and it will even work when landing on the Overview page first and navigating to the Overview page.
I will share my implementation with you, but be aware that it has some known bugs. E.g. you have to deal with z-indeces and overflows yourself; and it doesn't handle unregistering element positions from the store yet. I'm pretty sure if someone can spend some time on this, you can make a great little plugin out of it.
The implementation:
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import Overview from './Overview'
import DetailView from './DetailView'
import "./index.css";
import { Router, Route, IndexRoute, hashHistory } from 'react-router'
const routes = (
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Overview} />
<Route path="detail/:id" component={DetailView} />
</Route>
</Router>
)
ReactDOM.render(
routes,
document.getElementById('root')
);
App.js
import React, {Component} from "react"
import "./App.css"
export default class App extends Component {
render() {
return (
<div className="App">
{this.props.children}
</div>
)
}
}
Overview.js - Note the ID on the SharedElement
import React, { Component } from 'react'
import './Overview.css'
import items from './items' // Simple array containing objects like {title: '...'}
import { hashHistory } from 'react-router'
import SharedElement from './SharedElement'
export default class Overview extends Component {
showDetail = (e, id) => {
e.preventDefault()
hashHistory.push(`/detail/${id}`)
}
render() {
return (
<div className="Overview">
{items.map((item, index) => {
return (
<div className="ItemOuter" key={`outer-${index}`}>
<SharedElement id={`item-${index}`}>
<a
className="Item"
key={`overview-item`}
onClick={e => this.showDetail(e, index + 1)}
>
<div className="Item-image">
<img src={require(`./img/${index + 1}.jpg`)} alt=""/>
</div>
{item.title}
</a>
</SharedElement>
</div>
)
})}
</div>
)
}
}
DetailView.js - Note the ID on the SharedElement
import React, { Component } from 'react'
import './DetailItem.css'
import items from './items'
import { hashHistory } from 'react-router'
import SharedElement from './SharedElement'
export default class DetailView extends Component {
getItem = () => {
return items[this.props.params.id - 1]
}
showHome = e => {
e.preventDefault()
hashHistory.push(`/`)
}
render() {
const item = this.getItem()
return (
<div className="DetailItemOuter">
<SharedElement id={`item-${this.props.params.id - 1}`}>
<div className="DetailItem" onClick={this.showHome}>
<div className="DetailItem-image">
<img src={require(`./img/${this.props.params.id}.jpg`)} alt=""/>
</div>
Full title: {item.title}
</div>
</SharedElement>
</div>
)
}
}
SharedElement.js
import React, { Component, PropTypes, cloneElement } from 'react'
import { findDOMNode } from 'react-dom'
import TweenMax, { Power3 } from 'gsap'
export default class SharedElement extends Component {
static Store = {}
element = null
static props = {
id: PropTypes.string.isRequired,
children: PropTypes.element.isRequired,
duration: PropTypes.number,
delay: PropTypes.number,
keepPosition: PropTypes.bool,
}
static defaultProps = {
duration: 0.4,
delay: 0,
keepPosition: false,
}
storeNewPosition(rect) {
SharedElement.Store[this.props.id] = rect
}
componentDidMount() {
// Figure out the position of the new element
const node = findDOMNode(this.element)
const rect = node.getBoundingClientRect()
const newPosition = {
width: rect.width,
height: rect.height,
}
if ( ! this.props.keepPosition) {
newPosition.top = rect.top
newPosition.left = rect.left
}
if (SharedElement.Store.hasOwnProperty(this.props.id)) {
// Element was already mounted, animate
const oldPosition = SharedElement.Store[this.props.id]
TweenMax.fromTo(node, this.props.duration, oldPosition, {
...newPosition,
ease: Power3.easeInOut,
delay: this.props.delay,
onComplete: () => this.storeNewPosition(newPosition)
})
}
else {
setTimeout(() => { // Fix for 'rect' having wrong dimensions
this.storeNewPosition(newPosition)
}, 50)
}
}
render() {
return cloneElement(this.props.children, {
...this.props.children.props,
ref: element => this.element = element,
style: {...this.props.children.props.style || {}, position: 'absolute'},
})
}
}
I actually had a similar problem, where I had a search bar and wanted it to move and wrap to a different size and place on a specific route (like a general search in the navbar and a dedicated search page). For that reason, I created a component very similar to SharedElement above.
The component expects as props, a singularKey and a singularPriority and than you render the component in serval places, but the component will only render the highest priority and animate to it.
The component is on npm as react-singular-compoment
And here is the GitHub page for the docs.

Resources