Ionic Range If true, a pin with integer value is shown when the knob is pressed. can I pin by default show without pressed knob? - ionic4

If ionic range true, a pin with integer value is shown when the knob is pressed. can I pin by default show without pressed knob?

<ion-range #pin mode="md" min="0" max="100" pin="true" knob value="50" ></ion-range>
import { Component, OnInit, Input, ViewChild, AfterViewInit, ElementRef } from '#angular/core';
#Component({
selector: 'app-range',
templateUrl: './range.page.html',
styleUrls: ['./range.page.scss'],
})
export class RangePage implements OnInit, AfterViewInit {
time:any;
#ViewChild('pin', { static: true}) pin: ElementRef;
ngAfterViewInit(){
// #ts-ignore
let child = this.pin.el.shadowRoot.children
let timer = setInterval(() => {
if (child.length > 0){
this.getPin()
console.log(child);
clearInterval(timer)
}
});
}
getPin(){
// #ts-ignore
let children = this.pin.el.shadowRoot.children
let pinEl = [...children].filter(f => {
return f.className == 'range-slider'
})
let pin = pinEl[0].getElementsByClassName('range-pin')[0]
pin.style.transform = 'translate3d(0px, -24px, 0px) scale(1)'
}

Related

dispatch doesn't call reducer React Native

I create a component (AlertChild) to show alerts using redux in React-Native.
Currently when I call the dispatch from another component(another class)and this return, then the alertchild shows the message ok, but when I call the dispatch from the same component (Login), the alert is not showed and I can verify than the reducer (AlertReducer) is not called because the console.log() (in class AlertReducer) shows nothing.
AlertReducer:
export function AlertReducer(state = {}, action: any) {
console.log("Dispatch: " + action);
switch (action.type) {
case "INFO":
return {
alert: {
type: "info",
message: action.message,
},
};
case "DANGER":
return {
alert: {
type: "danger",
message: action.message,
},
};
case "CLEAR":
return {};
default:
return state;
}
}
AlertActions:
function showInfo(message: string) {
return {
type: "INFO",
message,
};
}
function showDanger(message: string) {
return {
type: "DANGER",
message,
};
}
function clear() {
return { type: "CLEAR" };
}
export const AlertActions = {
showInfo,
showDanger,
clear,
};
AlertChild:
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Toast } from "native-base";
import { AlertActions } from "../Store/Actions/AlertActions";
const AlertChild = (visible = true) => {
const alert = useSelector((state) => state.alert.alert);
const dispatch = useDispatch();
useEffect(() => {
ShowAlert();
}, [visible, dispatch]);
function ShowAlert() {
if (visible && alert !== undefined && Object.keys(alert).length) {
Toast.show({
text: alert.message,
buttonText: "X",
type: alert.type,
duration: alert.type === "danger" ? 60000 : 6000,
});
dispatch(AlertActions.clear());
}
}
return <></>;
};
export default AlertChild;
Login:
import React, { useState, useEffect, useContext } from "react";
import { Text, TextInput, View, Image } from "react-native";
import { Button, Spinner } from "native-base";
import styles from "./Styles/LoginStyles";
import { useDispatch } from "react-redux";
import AlertChild from "../Components/AlertChild";
import { AlertActions } from "../Store/Actions/AlertActions";
const Login = (props: any) => {
const { navigation } = props;
const dispatch = useDispatch();
useEffect(() => {
dispatch(AlertActions.clear());
}, [dispatch]);
async function Test() {
dispatch(AlertActions.showInfo("Hello"));
}
return (
<View style={styles.container}>
<Button onPress={async () => await Test()}>
<Text>Test</Text>
</Button>
<AlertChild {...props} />
</View>
);
};
export default Login;
Why the alert message is not displayed immediately?
I just needed to put in AlertChild the const "alert" (selector) in the useEffect:
useEffect(()=>{
ShowAlert()
},[visible, alert, dispatch])

How do I use mapDispatchToProps in place of directly accessing the Redux store?

I'm having trouble figuring out why my React Native component isn't preforming dispatching any of the actions I've tried to connected to it. I believe I've correctly followed the suggested approach to defining matchDispatchToProps as an object, but none of the expected actions seem to be happening.
Everything works fine if I explicitly import store. For example
store.dispatch({type: 'INCREMENT'})
works where the examples using just
increment
fails.
How do I correctly dispatch actions using mapDispatchToProps in place of directly accessing the Redux store?
In fact, I wonder why I would't just add something like
export const counterAPI = bindActionCreators(
{ increment, reset },
store.dispatch
)
in my store.ts (no longer exporting anything else from there, except store for use by Provider) and change
import { increment, reset } from "../store"
// ...
export default connect(null, mapDispatchToProps)(DemoCounter)
in DemoCounter.tsx to just
import { counterAPI } from "../store"
// ...
export default connect(null)(DemoCounter)
That seems to be a lot simpler and to achieve exactly the right level of modularity.
DemoCounter.tsx:
import React, { Component } from 'react'
import { View, Button, Text } from 'native-base'
import {connect} from "react-redux"
import { increment, reset } from "../store"
export class DemoCounter extends Component {
private timerID: number = 0
private interval = 1000
private startTimer(): void {
clearInterval(this.timerID)
this.timerID = setInterval(() => {
increment // Does nothing
}, this.interval)
}
componentDidMount(): void {
this.startTimer()
}
render() {
return (
<View>
<Button onPress={increment}> /* Does nothing */
<Text>Reset A</Text>
</Button>
<Button onPress={() => {reset(); this.startTimer()}}> /* How to combine action with other behaviors? */
<Text>Reset B</Text>
</Button>
<Button onPress={reset}> /* Does nothing */
<Text>Reset C</Text>
</Button>
</View>
)
}
}
const mapDispatchToProps = {
increment,
reset,
}
export default connect(null, mapDispatchToProps)(DemoCounter)
store.ts:
import {createStore} from "redux"
interface CounterState {
count: number;
}
const initialState: CounterState = {count: 0}
export type CounterAction =
| { type: 'INCREMENT' }
| { type: 'RESET' }
export const increment = (): CounterAction => ({ type: "INCREMENT" })
export const reset = (): CounterAction => ({ type: "RESET" })
const counterReducer = (state = initialState, action: CounterAction): CounterState => {
switch (action.type) {
case 'INCREMENT':
return {...state, count: state.count + 1}
case "RESET":
return {...state, count: 1}
default:
return state
}
}
export const store = createStore(counterReducer)
App.tsx:
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import { store } from "./store"
import PerspectiveCounter from "./components/PerspectiveCounter"
export default class App extends Component {
render() {
return (
<Provider store={store}>
<DemoCounter />
</Provider>
)
}
}
Hmmm...
I have never done it like that, so I am not sure what the problem is...
How about trying to define it my way? ;)
At least as a temporary workaround.
const mapDispatchToProps = (dispatch) => {
return {
increment: () =>
dispatch({ type: '"INCREMENT"'})
}
}
Any calling this.props.increment, of course.

ReactNative and NativeBase Radio

I've tried to change the radio value in ReactNative App with NativeBase template. I want to get or set value from the radio after click it, exactly checked or not. But couldn't find a way to get or set value to it. Even the radio button never changed on the screen after click. The codes are like as below:
import React, { Component } from 'react';
import { TouchableOpacity, Image, View } from 'react-native';
import { connect } from 'react-redux';
import { actions } from 'react-native-navigation-redux-helpers';
import {
Container,
Header,
Title,
Content,
Text,
Button,
Icon,
InputGroup,
Input,
List,
ListItem,
Radio, } from 'native-base';
import { openDrawer } from '../../actions/drawer';
import { Col, Row, Grid } from 'react-native-easy-grid';
import styles from './styles';
import dimension from './global';
import Swiper from 'react-native-swiper';
const imgBoy = require('../../../images/icon_boy.png');
const imgGirl = require('../../../images/icon_girl.png');
const {
popRoute,
} = actions;
class SessionPage extends Component {
static propTypes = {
name: React.PropTypes.string,
index: React.PropTypes.number,
list: React.PropTypes.arrayOf(React.PropTypes.string),
openDrawer: React.PropTypes.func,
popRoute: React.PropTypes.func,
navigation: React.PropTypes.shape({
key: React.PropTypes.string,
}),
}
popRoute() {
this.props.popRoute(this.props.navigation.key);
}
constructor(props) {
super(props);
// console.log(this.props.navigation);
this.state = {
sliderCount : parseInt(this.props.navigation.behavior.length / 5) + 1,
sliderArray : [],
selected : false,
}
this.getSliderArray();
console.log(this.state);
}
getSliderArray() {
for (var i = 0; i < this.state.sliderCount; i++) {
var childArray = [];
for (var j = i * 5; j < 5 * (i + 1); j++) {
if (this.props.navigation.behavior[j] != null){
var unit = this.props.navigation.behavior[j];
unit.selected = true;
childArray.push(unit);
}
}
this.state.sliderArray.push({
index : i,
behaviors : childArray
})
}
}
selectRadio(i, j){
this.state.sliderArray[i].behaviors[j].selected = true;
}
render() {
const { props: { name, index, list } } = this;
return (
<Container style={styles.container}>
<Swiper style={styles.wrapper}
height={dimension.Height - 400}
width={dimension.Width - 40}
showsButtons={false}
showsPagination={true}>
{this.state.sliderArray.map((item, i) =>
<View style={styles.slide1} key={i}>
{item.behaviors.map((subitem, j) =>
<ListItem key={i + "-" + j} style={styles.cardradio}>
<Radio selected={this.state.sliderArray[i].behaviors[j].selected} onPress={() => this.selectRadio(i, j)} />
<Text>{subitem.behaviorName}</Text>
</ListItem>
)}
</View>
)}
</Swiper>
</Content>
</Container>
);
}
}
function bindAction(dispatch) {
return {
openDrawer: () => dispatch(openDrawer()),
popRoute: key => dispatch(popRoute(key)),
};
}
const mapStateToProps = state => ({
navigation: state.cardNavigation,
name: state.user.name,
index: state.list.selectedIndex,
list: state.list.list,
});
export default connect(mapStateToProps, bindAction)(SessionPage);
selectRadio(i, j){
this.state.sliderArray[i].behaviors[j].selected = true; <== This is the problem
}
When you call this.state = something after the component has mounted, it doesn't trigger update method of component life cycle. Hence view will not be updated.
You should be using this.setState() to update your views
this.setState({
slider = something
})
For more info, refer docs
this.setState() is an async method. After you make changes in getSliderArray(), it may not be reflected in immediate console.log
this.getSliderArray();
console.log(this.state);
You can pass callback to this.setState() to perform any action only after state is changed
this.setState({
// new values
}, function() {
// Will be called only after switching to new state
})

Issue with unit testing of react component that uses "Material UI" using "Enzyme"

I have created two components LoginView and Login Form. LoginView uses LoginForm component for rendering. I am writing test cases for LoginView and LoginForm separately. The issue is when I import the LoginView and LoginForm component in a single spec, it works fine. But as I am trying to import same either components it raises an error
Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded.
The error says that
I might be using multiple copies of React, but I am using
react#15.3.2 and material-ui#0.15.4
The use of 'ref', I have not used 'ref' but Material-ui uses ref for
their component.
I am unable to solve issue, any help/ suggestions are appreciated.
Node v6.6.0
NPM 3.10.3
Files are:
LoginView:
import React from 'react';
import { FlatButton, Dialog } from 'material-ui';
import BaseComponent from './BaseComponent';
import LoginForm from './LoginForm';
export default class LoginView extends BaseComponent {
// statements
render(
<LoginForm onSubmit={this.handleSubmit} loading={loading} />
<br />
<FlatButton
secondary
onClick = { this.navToRegister }
label = {__('No Account? Create one.')}
/>
<br />
<FlatButton
secondary
onClick = { this.navToForgotPassword }
label = {__('Forgot your password?')}
/>
<br />
)
}
LoginForm:
import React from 'react';
import { TextField, RaisedButton } from 'material-ui';
export default class LoginForm extends React.Component {
// Statements
return (
<form onSubmit={this.handleSubmit}>
<TextField
type = "text"
/>
<br />
<TextField
type= "password"
/>
<br />
<RaisedButton
type = "submit"
/>
</form>
);
}
Spec Files:
Login Form:
import React from 'react';
import { mount } from 'enzyme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import LoginForm from '../../src/components/LoginForm';
import baseTheme from '../../src/style/muiThemes/neo';
describe('Login ', () => {
describe('LoginForm test case ', () => {
const context = { muiTheme: getMuiTheme(baseTheme) };
const email = 'test#mail.com';
const pass = 'testPassword';
let form = null;
let textField = null;
let emailInput = null;
let passwordInput = null;
let submitButton = null;
let submitSpy = null;
let wrapper = null;
beforeEach(() => {
submitSpy = chai.spy.on(LoginForm.prototype, 'handleSubmit');
wrapper = mount(<LoginForm onSubmit={submitSpy} />, { context });
form = wrapper.find('LoginForm');
textField = wrapper.find('TextField');
emailInput = textField.get(0);
passwordInput = textField.get(1);
submitButton = wrapper.find('button[type="submit"]');
});
// Some test scenarios
}
Login View:
import React from 'react';
import { mount } from 'enzyme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import LoginView from '../../src/components/LoginView'; // Error while importing this file.
import baseTheme from '../../src/style/muiThemes/neo';
describe('LoginView test cases', () => {
const context = { muiTheme: getMuiTheme(baseTheme) };
let submitSpy = null;
let wrapper = null;
let loginForm = null;
beforeEach(() => {
submitSpy = chai.spy.on(LoginView.prototype, 'handleSubmit');
wrapper = mount(<LoginView onSubmit={submitSpy} />, { context });
loginForm = wrapper.find('LoginForm');
});
it('calls componentDidMount', () => {
const spy = chai.spy.on(LoginView.prototype, 'componentDidMount');
wrapper = mount(<LoginView />, { context });
expect(spy).to.have.been.called.once;
});
it('Access the dom', () => {
expect(loginForm).not.to.equal(undefined);
});
});

Angular2 Component listen when parent's resize change

I have a requirement in which I want to change properties of a child component depending on the size of its parent component though a method call. The issue I am running into is that the only resize event I can listen to is that of the window, which doesn't help as the window size is not changing, only the parent component is due to a side panel div opening and closing.
The only possibility I can see at the moment is to have some sort of polling in which we within the child component itself that checks if its width has changed every x amount of time.
Thanks for your help!
You are correct that you can't get the resize event on a div (without installing some js extension). But something like this works.
The Parent Component:
import {Component, AfterContentInit, ElementRef} from '#angular/core';
import { ChildComponent } from "./ChildComponent";
export interface IParentProps {
width: number;
height: number;
}
#Component({
selector: 'theParent',
template: `text text text text text text
text text text text text text
<the-child [parentProps]="parentProps"></the-child>`,
directives: [ChildComponent]
})
export class ParentComponent implements AfterContentInit {
sizeCheckInterval = null;
parentProps: IParentProps = {
width: 0,
height: 0
}
constructor(private el: ElementRef) {
}
ngAfterContentInit() {
this.sizeCheckInterval = setInterval(() => {
let h = this.el.nativeElement.offsetHeight;
let w = this.el.nativeElement.offsetWidth;
if ((h !== this.parentProps.height) || (w !== this.parentProps.width)) {
this.parentProps = {
width: w,
height: h
}
}
}, 100);
}
ngOnDestroy() {
if (this.sizeCheckInterval !== null) {
clearInterval(this.sizeCheckInterval);
}
}
}
The Child Component:
import {Component, Input, SimpleChange} from "#angular/core";
import { IParentProps } from "./ParentComponent";
#Component({
directives: [],
selector: "the-child",
template: `child`
})
export class ChildComponent {
#Input() parentProps: IParentProps;
constructor() {
this.parentProps = {
width: 0,
height: 0
}
}
ngOnChanges(changes: { [propName: string]: SimpleChange }) {
this.parentProps = changes["parentProps"].currentValue;
console.log("parent dims changed");
}
}