Material-UI Drawer with Appbar not working with component syntax - drawer

I have created a new thread from this one to avoid confusion as someone told me that Leftnav is now Drawer within the Material-UI components.
I am still having problems, the first which is the ES7? syntax of the arrow functions shown here. I have changed to the following code with flat links for now to try to understand what is going on:
import React, { Component } from 'react'
import { Drawer, AppBar, MenuItem} from 'material-ui'
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme'
import getMuiTheme from 'material-ui/styles/getMuiTheme'
import { Route, Router } from 'react-router'
export default class Header extends Component {
constructor(props){
super(props);
this.state = {open:false};
}
getChildContext() {
return {muiTheme: getMuiTheme(baseTheme)};
}
handleToggle() {
this.setState({open: !this.state.open});
console.log("open")
}
handleClose() { this.setState({open: false}); }
render() {
return (
<div>
<Drawer
docked={false}
open={false}>
<MenuItem onTouchTap={this.handleClose}>Menu Item 1</MenuItem>
<MenuItem onTouchTap={this.handleClose}>Menu Item 2</MenuItem>
<MenuItem onTouchTap={this.handleClose}>Menu Item 3</MenuItem>
</Drawer>
<AppBar title="App Bar Example"
isInitiallyOpen={true} onLeftIconButtonTouchTap={this.handleToggle} onLeftIconButtonClick={this.handleToggle} />
</div>
);
}
}
Header.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};
export default Header;
I am now getting no errors but it does not work. I have added onLeftIconButtonClick={this.handleToggle} to try getting the hamburger menu toggling the Drawer but nothing happens. Is there any documentation about SYNTAX, parametres or any reference material I can look in order to implement this material-ui framework?

There's also another important detail, you have to bind "this" in:
onLeftIconButtonTouchTap={this.handleToggle.bind(this)}
And in:
<MenuItem onTouchTap={this.handleClose.bind(this)}>Menu Item 1</MenuItem>
<MenuItem onTouchTap={this.handleClose.bind(this)}>Menu Item 2</MenuItem>
<MenuItem onTouchTap={this.handleClose.bind(this)}>Menu Item 3</MenuItem>

The open prop of Drawer should point to your state:
<Drawer
docked={false}
open={this.state.open}
>
...
</Drawer>

I ended up with this:
import React from 'react';
// import { Drawer, AppBar, MenuItem} from 'material-ui'
// This is faster & creates smaller builds:
import Drawer from 'material-ui/Drawer';
import AppBar from 'material-ui/AppBar';
import MenuItem from 'material-ui/MenuItem';
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme'
import getMuiTheme from 'material-ui/styles/getMuiTheme'
export default class Header extends React.Component {
constructor(props){
super(props);
this.state = {open:false};
}
getChildContext() {
return {muiTheme: getMuiTheme(baseTheme)};
}
handleToggle() {
this.setState({open: !this.state.open});
console.log("open")
}
handleClose() { this.setState({open: false}); }
render() {
return (
<div>
<Drawer
docked={false}
open={this.state.open}
onRequestChange={(open) => this.setState({open})}
>
<MenuItem onTouchTap={this.handleClose.bind(this)}>Menu Item 1</MenuItem>
<MenuItem onTouchTap={this.handleClose.bind(this)}>Menu Item 2</MenuItem>
<MenuItem onTouchTap={this.handleClose.bind(this)}>Menu Item 3</MenuItem>
</Drawer>
<AppBar title="App Bar Example"
onLeftIconButtonTouchTap={this.handleToggle.bind(this)} />
</div>
);
}
}
Header.childContextTypes = {
muiTheme: React.PropTypes.object.isRequired,
};

Related

How to hook data-grid events in parent lit-element component?

I want to react on events started by elements placed in the data-grid rows.
Vaading data-grid prevents events from bubbling up to the parent component containing the grid. Having buttons placed in the grid column rendered for each row I cannot catch the click or any other event from the component that hosts the grid.
The examples from https://vaadin.com/components/vaadin-grid/html-examples are relying on js hooks being attached in the html file. I am working with Lit-element and trying to do the same at firstUpdated() callback. The problem is that apparently at this point the table is not available.
<vaadin-grid id="test" .items=${this.data} theme="compact">
<vaadin-grid-column width="40px" flex-grow="0">
<template class="header">#</template>
<template>
<vaadin-button style="font-size:10px;" theme="icon" focus-target #click="${(e) => { console.log(e) }}">
<iron-icon icon="icons:create"></iron-icon>
</vaadin-button>
</template>
</vaadin-grid-column>
</vaadin-grid>
I expected to have the log and nothing happens as the grid component prevents event from bubbling up to my component.
The code that tries to implement renderer property for vaadin-grid-column:
import { LitElement, html, css } from 'lit-element'
import {render} from 'lit-html';
import '#vaadin/vaadin-grid/vaadin-grid.js'
import '#vaadin/vaadin-grid/vaadin-grid-filter-column.js'
import '#vaadin/vaadin-grid/vaadin-grid-sort-column.js';
import '#vaadin/vaadin-grid/vaadin-grid-filter.js';
import '#vaadin/vaadin-grid/vaadin-grid-sorter.js'
export default class MyClass extends LitElement {
static get properties () {
return {
data: {
type: Array,
hasChanged: () => true
},
}
}
get grid() {
return this.shadowRoot.querySelector('vaadin-grid');
}
constructor () {
super()
this.data = []//is being assigned from super as a property to a custom element
}
render () {
return html`
<vaadin-grid id="test" .items=${this.data}>
<vaadin-grid-column .renderer=${this.columnRenderer} header="some header text"></vaadin-grid-column>
</vaadin-grid>
`
}
columnRenderer(root, column, rowData) {
render(html`test string`, root);
}
}
window.customElements.define('my-elem', MyClass)
When using vaadin-grid inside LitElement-based components you should use renderers
Here's how your code would look using renderers
import {LitElement, html} from 'lit-element';
// you need lit-html's render function
import {render} from 'lit-html';
class MyElement extends LitElement {
// we'll just assume the data array is defined to keep the sample short
render() {
return html`
<vaadin-grid id="test" .items=${this.data} theme="compact">
<vaadin-grid-column width="40px" flex-grow="0" .renderer=${this.columnRenderer} .headerRenderer=${this.columnHeaderRenderer}></vaadin-grid-column>
<vaadin-grid>
`;
}
columnHeaderRenderer(root) {
render(html`#`, root);
// you could also just do this
// root.textContent = '#'
// or actually just use the column's header property would be easier tbh
}
columnRenderer(root, column, rowData) {
render(
html`
<vaadin-button style="font-size: 10px;" theme="icon" focus-target #click="${(e) => { console.log(e) }}">
<iron-icon icon="icons:create"></iron-icon>
</vaadin-button>
`, root);
}
}
You can see this and more of vaadin-grid's features in action in LitElement in this Glitch created by one of the vaadin team members

Reactjs with Rails, remove duplicated createMuiTheme

the code below is one of my component.
i am creating this with Ruby on Rails framework, with react_rails gem and webpacker, experimenting on Material UI.
as you can see, i am changing the Material UI default font theme with my own choice of font. below code is a success.
my question is, do i have to repeat this step for all my component?
importing createMuiTheme, stating the theme const, and wrapping <MuiThemeProvider /> in every render?
is there a single way to do this universally, without repeating in all component?
thanks for the advice.
import React from 'react';
import PropTypes from 'prop-types';
import Card from '#material-ui/core/Card';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import Button from '#material-ui/core/Button';
import Popover from '#material-ui/core/Popover';
import Typography from '#material-ui/core/Typography';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
import Avatar from '#material-ui/core/Avatar';
import EmailIcon from '#material-ui/icons/Email';
import HomeIcon from '#material-ui/icons/Home';
import PersonIcon from '#material-ui/icons/Person';
import { MuiThemeProvider, createMuiTheme, withStyles } from '#material-ui/core/styles';
const theme = createMuiTheme({
typography: {
fontFamily: 'Bebas',
},
});
export class SimpleCard extends React.Component {
render () {
return (
<div >
<MuiThemeProvider theme={theme}>
<Card raised="true">
<CardContent >
<List>
<ListItem>
<Avatar>
<EmailIcon />
</Avatar>
<ListItemText primary="Email" secondary={this.props.order.order_mail} />
</ListItem>
</List>
</CardContent>
</Card>
</MuiThemeProvider>
</div>
);
}
}
export default withStyles(styles)(SimpleCard);
Did you try wrapping the MuiThemeProvider around the entire site/app? This is what I do in React.js. I set up my theme in the root file and wrap it around the entire component
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
// Components
import Navbar from "./components/layout/Navbar";
import Footer from "./components/layout/Footer";
import Login from "./components/auth/Login";
import Dashboard from "./components/dashboard/Dashboard";
// Styles
import "./stylesheets/App.css";
import {
MuiThemeProvider,
createMuiTheme,
withTheme
} from "#material-ui/core/styles";
import { grey } from "#material-ui/core/colors";
import { withStyles } from "#material-ui/core";
const theme = createMuiTheme({
overrides: {
MuiGrid: {
container: {
width: "100%",
margin: "0"
}
}
},
palette: {
primary: {
light: "#c146b1",
main: "#8e0081",
dark: "#5c0054",
contrastText: "#ffffff"
},
secondary: {
light: "#6bffff",
main: "#00eae3",
dark: "#00b7b1",
contrastText: "#000000"
}
}
});
const drawerWidth = 240;
const styles = theme => ({
app: {
backgroundColor: grey[200]
},
drawerOpen: {
marginLeft: 0
},
drawerClosed: {
marginLeft: -drawerWidth
}
});
class App extends Component {
constructor() {
super();
this.state = {
navOpen: false
};
}
toggleDrawer = () => {
this.setState({
navOpen: !this.state.navOpen
});
};
render() {
const { classes } = this.props;
return (
<MuiThemeProvider theme={theme}>
<div className={classes.app}>
<Navbar
toggleDrawer={this.toggleDrawer}
navOpen={this.state.navOpen}
/>
<Route exact path="/" component={Dashboard} />
<Route exact path="/register" component={PatientRegister} />
<Route exact path="/login" component={Login} />
<Footer />
</div>
</Router>
</MuiThemeProvider>
);
}
}
export default withTheme(theme)(withStyles(styles)(App));
This is an example of my component that will be rendered in the root div (aka the entire application). Notice how wraps the entire app? I stripped a lot out to make it simpler to understand, but if you are using Redux (which is awesome) then I would recommend having that as your outer wrapper, and the rest inside of that. In other words:
<Provider store={store}>
<MuiThemeProvider theme={theme}>
<div class="App">
// Your App Here
</div>
</MuiThemeProvider>
</Provider>

React Native tabbar flickering

I have used React native native base library for Tabbar with 4 screens but it is flickering while switch tabs.
import React, { Component } from 'react';
import { Container, Header, Content, Tab, Tabs } from 'native-base';
import Tab1 from './tabOne';
import Tab2 from './tabTwo';
​export default class TabsExample extends Component {
render() {
return (
<Container>
<Header hasTabs />
<Tabs initialPage={1}>
<Tab heading="Tab1">
<Tab1 />
</Tab>
<Tab heading="Tab2">
<Tab2 />
</Tab>
<Tab heading="Tab3">
<Tab3 />
</Tab>
</Tabs>
</Container>
);
}
}
I had a similar problem when I developed an app as well in react-native. The problem for me was that I had used componentsWillUpdate for animations. Instead I did a helper function for the animations.
Don't know how the rest of your code looks like but this solved my problem.
You can be here that you want to
1, Install: switch-react-native
npm i switch-react-native
2, Using lib:
import React, { Component } from 'react';
import { View } from 'react-native';
import { Switch } from 'switch-react-native';
class SwitchExample extends Component {
render() {
return (
<View>
<Switch
height={40}
width={300}
activeText={`Active Text`}
inActiveText={`InActive Text`}
onValueChange={(value: any) => console.log(value)}
/>
</View>
);
}
}

Programmatically open an N level self nested mat-menu component with matMenuTrigger openMenu

I am trying to make a self nested component that uses Angular Material mat-menu. I have a flyoutcomponent that is a wrapper for flyout-menu-item component, that will have a button as a matMenuTrigger for the nested component that will appear as many levels as the FeatureInput.FeatureChoices dictates. FeatureInput is an object that has FeatureChoices that may or may not contain other featurechoices etc N levels deep. Below code does not compile but it should demonstrate what I am doing. Basically I have flyout menu component as a input to a form and I am trying to load a stored answer on a form rather than select new, which I can do easily using the nested component. The desired behavior is that if the user clicks top matMenuTrigger button to open the top menu that it would expand all child menus to the menu item that matches with the FeatureInput.FeatureValue and sets the menu item _highlighted to true. I am using the menuOpen input parameter and ngChanges successfully to find the match(with I a setTimeout which cannot be right). Basically when I console.log this.trigger it is undefined. Ideally in the ngOnChange to the openMenu I would go through all menus and call openMenu on all the triggers but I cannot get access to the matMenuTrigger with ViewChild as the docs say. I get undefined. *-( All help welcome please and thanks.
Here is flyout template component.
<div>
<buttonmat-button [matMenuTriggerFor]="menu.childMenu"
(onMenuOpen)="onMenuOpen()"
(onMenuClose)="onMenuClose()">
<span [innerHTML]="featureInput.Text"></span>
</button>
<app-flyout-menu-item #menu
[featureChoicesObject]="featureInput.FeatureChoices"></app-flyout-menu-item>
</div>
And here is its .ts
import { Component, OnInit, Input, ViewChild } from '#angular/core';
import { MatMenuTrigger } from '#angular/material';
#Component({
selector: 'app-flyout',
templateUrl: './flyout.component.html',
styleUrls: ['./flyout.component.scss']
})
export class FlyoutComponent implements OnInit {
#Input() featureInput: FeatureInput
constructor() { }
ngOnInit() {
}
onMenuOpen() {
this.menuOpen = true;
}
onMenuClose() {
this.menuOpen = false;
}
}
And here is flyout-menu-item template
<mat-menu #childMenu="matMenu" [overlapTrigger]="false">
<span *ngFor="let featureChoice of featureChoices">
<span>
<button mat-menu-item [matMenuTriggerFor]="menu.childMenu">
<span [innerHTML]="featureChoice.Text"></span>
</button>
<app-flyout-menu-item #menu
[menuOpen]="menuOpen"
[featureInput]="featureInput"
[featureChoicesObject]="featureChoice.FeatureChoices"
(onOptionSelected)="someService.SomeMethod($event)"></app-flyout-menu-item>
</span>
<span *ngIf="!featureChoice.FeatureChoices">
<button mat-menu-item (click)="selectOption(featureChoice.ID)" [innerHTML]="featureChoice.Text" value="{{featureChoice.ID}}"></button>
</span>
</span>
</mat-menu>
And here is its .ts
import { Component, OnInit, Input, Output, ViewChild, EventEmitter, OnChanges, SimpleChanges } from '#angular/core';
import { MatMenuTrigger } from '#angular/material';
import { FeatureChoice } from 'app/model/feature-choice';
import { FeatureInput } from 'app/model/feature-input';
#Component({
selector: 'app-flyout-menu-item',
templateUrl: './flyout-menu-item.component.html',
styleUrls: ['./flyout-menu-item.component.scss']
})
export class FlyoutMenuItemComponent implements OnInit{
#ViewChild('menu') public menu;
#ViewChild('childMenu') public childMenu;
#ViewChild(MatMenuTrigger) public trigger: MatMenuTrigger;
#Input() featureInput: FeatureInput;
#Input() featureChoicesObject: FeatureChoice;
#Output() onOptionSelected: EventEmitter<FeatureInput> = new EventEmitter<FeatureInput>();
constructor(public solutionDataService: SolutionDataService) { }
ngOnInit() {
console.log(this.trigger);
}
ngOnChanges(simpleChanges: SimpleChanges) {
if (simpleChanges.menuOpen && simpleChanges.menuOpen.currentValue) {
setTimeout(() => {
// console.log(this.menu);
const itemsArray = this.childMenu.items.toArray();
for (let x = 0; x < itemsArray.length; x++) {
const menuItem = itemsArray[x];
if (this.featureInput.FeatureValue !== '' && menuItem._elementRef.nativeElement.value === this.featureInput.FeatureValue) {
menuItem._highlighted = true;
}
}
}, 1);
}
}
}
this.menuOpen = true;
Perhaps add menuOpen: boolean = false as an attribute at the top of your FlyoutComponent. I don't know where the value of menuOpen is saved.
the menuOpen property relates to the matMenuTrigger.
here's an example:
<button [ngClass]="{'active-icon': trigger.menuOpen}" type="button" mat-
icon-button #trigger="matMenuTrigger" [matMenuTriggerFor]="help">
<mat-icon></mat-icon>
</button>
<mat-menu #help="matMenu">
<div> textId </div>
</mat-menu>

Navigation iOS in React Native

I've looked at many different Stack Overflow posts about how to navigate screens in React Native but none of them seem to be working, perhaps because those posts were for older versions of React Native. Here is my code with the irrelevant parts taken out below. I'm trying to navigate from this screen to another screen called SubTasks. I made sure to say export default class SubTasks extends React.Component in SubTasks.js, by the way. The error I'm getting when I click on the button is "undefined is not an object (evaluating this.props.navigator.push'). Does anyone know where my error may be?
import React, { Component, PropTypes } from 'react';
import { StyleSheet,NavigatorIOS, Text, TextInput, View, Button}
from 'react-native';
import SubTasks from './SubTasks';
export default class App extends React.Component {
constructor(props) {
super(props);
}
renderScene(route, navigator) {
if(route.name == 'SubTasks') {
return <SubTasks navigator = {navigator} />
}
}
_navigate() {
this.props.navigator.push({
title: 'SubTasks',
})
}
render() {
return (
<View>
<NavigatorIOS
initialRoute= {{
title: 'SubTasks',
component: SubTasks,
}}
style = {{ flex: 1 }}
/>
<Button
title= 'SubTasks'
style = {{flexDirection: 'row', fontSize: 20, alignItems: 'flex-end'}}
color = 'blue'
onPress= {() => this._navigate()}>
styleDisabled = {{color: 'red'}}
</Button>
</View>
)}
}
Make sure you bind your _navigate function in your constructor:
constructor(props) {
super(props);
this._navigate = this._navigate.bind(this);
}
Or consider using arrow function
_navigate = () => {
this.props.navigator.push({
title: 'SubTasks',
})
}

Resources