am trying to make an instance of ClassOne in ClassTwo in the code below, however I get errors Invalid constructor name and Undefined class 'instOne .person how do I do this the right way
class ClassOne extends StatefulWidget {
#override
ClassOneState createState() => ClassOneClassState();
}
class ClassOneState extends State<ClassOneClass> {
var person= 'myname';
hey(){
print('hey hello');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView(
children: <Widget>[
],
),
);
}
}}
// the file is in main.dart
import 'package:cloud_fs_demo/main.dart' ;
class ClassTwo extends StatefulWidget {
#override
ClassTwoState createState() => ClassTwoClassState();
}
class ClassTwoState extends State<ClassTwoClass> {
ClassOne instOne = ClassOne();
//Undefined class 'instOne .person'
instOne .person;
//error:Invalid constructor name
instOne .hey() ;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ListView(
children: <Widget>[
],
),
);
}
}}
you can create instance of ClassOne in ClassTwo because you are defining a field but think about this : when this code will execute ? instOne.person; . now to solve the problem you have to execute this code in the constructor function or in the initstate of the widget and the difference between them that the constructor method is executed first
in the constructor function
var instone= ClassOne();
_ClassTwoState(){
instone.person="test";
}
in the initstate of the widget
#override
void initState() {
instone.person="test";
super.initState();
}
also you have to declare the fields and the functions you are going to use in ClassTwo not in ClassTwoState
class ClassOne extends StatefulWidget {
var person= 'myname';
hey(){
print('hey hello');
}
#override
ClassOneState createState() => ClassOneState();
}
full example
Related
I'm having an issue where a component isn't rerendering. There's a base class that's needed to be overriden in order to perform testing.
I'm expecting it to fire after the handleChange function is called because someone typed in the textbox.
BASE CLASS
import * as React from 'react';
import { ISiteListRendererProps } from "./SiteListRendererProps";
import { SitelistState, SiteItem } from './ISitelistState';
export default class SiteListRendererBase extends React.Component<ISiteListRendererProps, SitelistState> {
public SiteItemsPremise : SiteItem[];
public SiteItemsOnline : SiteItem[];
public SearchText: string;
public constructor(props) {
super(props);
}
public render(): React.ReactElement<ISiteListRendererProps> {
return (<div id="SiteListRendererNull"></div>);
}
}
CHILD CLASS
import * as React from 'react';
import { ISiteListRendererProps } from "./SiteListRendererProps";
import SiteListRendererBase from './SiteListRendererBase';
export default class SiteListRenderer extends SiteListRendererBase {
public constructor(props) {
super(props);
this.state = {SearchText: "", SiteItemsPremise: null, SiteItemsOnline: null, OnPremiseUrl: null};
//this.handleChange = this.handleChange.bind(this);
}
public render(): React.ReactElement<ISiteListRendererProps> {
console.log("rerender: " + this.state.SearchText);
console.log(this.SearchText);
let siteItems = this.SiteItemsPremise.concat(this.SiteItemsOnline);
siteItems.sort((a, b) => (a.Title > b.Title ? 1 : -1));
return (
<div>
<div>
<input type="text" onChange={this.handleChange} />
</div>
{siteItems
.filter(
(item, index) =>
this.state.SearchText.length == 0 ||
item.Title.toUpperCase().indexOf(
this.state.SearchText.toUpperCase()
) >= 0
)
.map((item, index) => (
<p key={item.Url}>
{item.Title + " (" + item.Location + ")"}{this.SearchText}
</p>
))}
</div>
);
}
handleChange = (e) => {
this.setState({ SearchText: e.target.value});
this.forceUpdate();
}
}
PROPS AND STATE FOR COMPLETENESS
export class SitelistState {
public SiteItemsOnline: SiteItem[];
public SiteItemsPremise: SiteItem[];
public SearchText: string;
public OnPremiseUrl: string;
}
export class SiteItem {
public Title: string;
public Url: string;
public Location: string;
public WebTemplate: string;
}
export interface ISiteListRendererProps {
SiteItemsPremise : SiteItem[];
SiteItemsOnline : SiteItem[];
SearchText: string;
}
I have an Sharepoint app. By clicking on a command list button I open a panel.
But when I try to close the panel I get a error saying that my _renderPanelComponent function is not a function and when trying to log it from _dismissPanel() it I get that it is undefined. But I can call it from _showPanel().
By logging from _dismissPanel() I now that I get back here after clicking close and triggered _onCancel() but I'm not sure why my _renderPanelComponent gets undefined and thats my question.
This is what the code looks like
import { override } from '#microsoft/decorators';
import { Log } from '#microsoft/sp-core-library';
import {
BaseListViewCommandSet,
Command,
IListViewCommandSetListViewUpdatedParameters,
IListViewCommandSetExecuteEventParameters
} from '#microsoft/sp-listview-extensibility';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { assign } from '#uifabric/utilities';
import MainPanel, { IMainPanelProps } from '../MainPanel';
export interface ICreditInfoCommandSetProperties {
sampleTextOne: string;
sampleTextTwo: string;
context:object;
}
export default class CreditInfoCommandSet extends BaseListViewCommandSet<ICreditInfoCommandSetProperties> {
private panelPlaceHolder: HTMLDivElement = null;
public _renderPanelComponent(props: any) {
const element: React.ReactElement<IMainPanelProps> = React.createElement(MainPanel, assign({
isOpen: false,
onClose: null,
context: this.context
}, props));
ReactDom.render(element, this.panelPlaceHolder);
}
private _showPanel() {
this._renderPanelComponent({
isOpen: true,
onClose: this._dismissPanel,
context: this.context
});
}
private _dismissPanel() {
console.log(typeof(this._renderPanelComponent))
this._renderPanelComponent({ isOpen: false});
}
#override
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, 'Initialized CreditInfoCommandSet');
this.panelPlaceHolder = document.body.appendChild(document.createElement("div"));
return Promise.resolve();
}
#override
public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
}
#override
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
switch (event.itemId) {
case 'COMMAND_2':
this._showPanel();
break;
default:
throw new Error('Unknown command');
}
}
}
And this is what my panel looks like
import * as React from 'react';
// Custom imports
import { Panel, PanelType , TextField, Checkbox, DefaultButton, PrimaryButton, Dropdown, IDropdownOption} from 'office-ui-fabric-react';
import style from "./MainPanelStyle.module.scss";
export interface IMainPanelProps {
onClose: () => void;
isOpen: boolean;
}
export interface IMainPanelState {}
export default class MainPanel extends React.Component<IMainPanelProps, IMainPanelState> {
constructor(props: IMainPanelProps, state: IMainPanelState) {
super(props);
this.state = {}
private _onCancel = () => {
this.props.onClose();
}
public render(): React.ReactElement<IMainPanelProps> {
return (
<div>
<Panel isLightDismiss={true} isOpen={this.props.isOpen} type={PanelType.medium} onDismiss={this.props.onClose}>
<DefaultButton className={style.closeButton} text="Close" onClick={this._onCancel}/>
</Panel>
</div>
);
}
}
I ran into this too. Changing this
private _dismissPanel() {
to
private _dismissPanel = () =>{
Got this working for me, as it binds the method to the scope of its class so this can be properly resolved. I realize this is an old post but just in case any one else runs into this issue.
In this component I get a Promise object in the properties, I try to put it in state, but when the view is rendered, I get the message "TypeError: Cannot read property 'vote' of null", asking for a solution to my problem, I spent two hours on it and I don't see the end. What should I do differently?
import { IVoteDetailsProps } from "./IVoteDetailsProps";
import { IVoteDetailsState } from "./IVoteDetailsState";
export class VoteDetails extends React.Component<IVoteDetailsProps, IVoteDetailsState>{
constructor(props: IVoteDetailsProps) {
super();
console.log(props)
}
componentDidMount() {
let data = this.props.voteDetails;
data.then(result => this.setState({
vote: result
}));
};
public render(): React.ReactElement<IVoteDetailsState> {
return (
<table >
<tbody>
{this.state.vote && this.state.vote.map(el => {
<tr id={el.id.toString()}>
<td>{el.title}</td>
<td>{el.voteType}</td>
</tr>
})}
</tbody>
</table>
)
}
}
export interface IVoteDetailsProps {
voteDetails: Promise<IVoteDetailsData[]>;
}
export interface IVoteDetailsData{
id: number;
title: string;
voteType: string;
}
import React = require("react");
import { VoteDetails } from "../VoteDetails/VoteDetails";
import { IVoteListProps } from "./IVoteListProps";
export class VoteList extends React.Component<IVoteListProps, {}> {
constructor(props: IVoteListProps) {
super(props);
console.log(props)
}
public render(): React.ReactElement<IVoteListProps> {
// const { vote } = this.state;
return (
<VoteDetails voteDetails={this.props.adminServicePanel.getVotesInfo()} />
)
};
}
public render(): React.ReactElement<IVoteSecurityAppProps> {
return (
<main className="ui main text container">
<VoteList adminServicePanel={this.props.adminPanelService}/>
</main>
);
import {HttpClient} from '#microsoft/sp-http';
import { reject } from 'lodash';
import {IAdminPanelService} from './IAdminPanelService';
import {IReportData} from './IReportData'
import { IVoteDetailsData } from './IVoteDetailsData';
import {IVoteInfo} from './IVoteInfo'
import {VoteOptions} from './VoteOptions';
export class AdminPanelService implements IAdminPanelService {
//////////////////////////////MOCK////////////////////////////////////////////
private voteInfos : IVoteDetailsData[];
private reportData : IReportData[];
//////////////////////////////MOCK////////////////////////////////////////////
constructor(private httpClient: HttpClient, private serverRelativeSiteUrl: string) {
//MOCK
this.voteInfos = [
{
id : 1,
title : "xxx",
voteType : "xx"
},
{
id : 2,
title : "xxx",
voteType : "xxx"
}
];
}
public getVotesInfo () : Promise<IVoteDetailsData[]> {
return new Promise<IVoteDetailsData[]>((resolve : (voteMiniInfo : IVoteDetailsData[]) => void, reject : (error: any) => void): void =>{
resolve(this.voteInfos);
})
}
}
export interface IAdminPanelService {
getVotesInfo:() => Promise<IVoteDetailsData[]>;
}
import * as React from 'react';
import styles from './VoteSecurityApp.module.scss';
import { IVoteSecurityAppProps } from './IVoteSecurityAppProps';
import { escape } from '#microsoft/sp-lodash-subset';
import { VoteList } from './VoteList/VoteList';
export default class VoteSecurityApp extends React.Component<IVoteSecurityAppProps, {}> {
public render(): React.ReactElement<IVoteSecurityAppProps> {
return (
<main className="ui main text container">
<VoteList adminServicePanel={this.props.adminPanelService}/>
</main>
);
}
}
export class VoteDetails extends React.Component<IVoteDetailsProps, IVoteDetailsState>
{
state = {
vote: null,
}
// change this
componentDidMount() {
this.props.voteDetails().then(result => this.setState({
vote: result
}));
};
// rest of your codes here
}
export class VoteList extends React.Component<IVoteListProps, {}> {
constructor(props: IVoteListProps) {
super(props);
console.log(props)
}
public render(): React.ReactElement<IVoteListProps> {
// const { vote } = this.state;
return (
<VoteDetails voteDetails=
{this.props.adminServicePanel.getVotesInfo} /> // change this line
)
};
}
All errors "TypeError: Cannot read property '......' of null" in spfx components, when you call
this.state.{varname}
or
this.props.{varname}
solves one of:
Add binding 'this' in constructor to method where rise error
this.{methodname} = this.{methodname}.bind(this)
You miss initialize state in constructor (for React.Component<props,state>)
this.state = {};
You use value from props or state and miss check it for null
In question I see all of this things. For example, in this peice of code state will not be initialized, otherwise component has state
export class VoteDetails extends React.Component<IVoteDetailsProps, IVoteDetailsState>{
constructor(props: IVoteListProps) {
super(props);
console.log(props)
//this.state == null - true
}
}
Second problem is this code
<VoteDetails voteDetails={this.props.adminServicePanel.getVotesInfo()}
getVotesInfo- return promise, not data. This bad practice, use state to hold data, for example
constructor(props: ...){
super(props);
this.state{
data: null
};
this._getData = this._getData.bind(this);
}
componentDidMount(){
this._getData();
}
async _getData(){
if(this.props.adminServicePanel){
let data = await this.props.adminServicePanel.getVotesInfo();
this.setStae({data});
}
}
render():...{
const data = this.state.data;
return(
{data && data.map(...)}
);
}
I am having problems with a larger application that is using sqflite. So I created this simple app to test a few things and I noticed that the app is creating a journal file in the emulator and not removing it. Is this by design or an issue with the emulator or sqflite?
If this is by design, I guess it would be common practice to have to cleanup these files along with the database file. That seems like a bit messy but doable I guess. I am hoping is it just a problem with the emulator.
import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyClass myClass;
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: AppWg());
}
}
class AppWg extends StatefulWidget {
AppWg({Key key}) : super(key: key);
#override
_AppWgState createState() => _AppWgState();
}
class _AppWgState extends State<AppWg> {
MyClass myClass = MyClass();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Test")), body: getView(context));
}
Widget getView(BuildContext context) {
return Column(
children: [
Text("path:" + myClass.path),
Text("message:" + myClass.message),
RaisedButton(
child: Text("action"),
onPressed: () {
onAction();
})
],
);
}
void onAction() {
getApplicationDocumentsDirectory().then((dir) {
String path = join(dir.path, "db1.db");
print(path);
myClass.createDb(path).then((result) {
setState(() {});
});
});
}
}
class MyClass {
Database db;
String path = "";
String message = "";
Future<bool> createDb(p) async {
try {
path = p;
message = "attempting delete/create";
File file = File(path);
if (await file.exists()) {
await file.delete();
}
if (!(await file.exists())) {
db = await openDatabase(path, onConfigure: (db) {
String qs = "PRAGMA foreign_keys = ON";
db.execute(qs);
});
await db.execute("CREATE TABLE T1 (ID INTEGER PRIMARY KEY)");
await db.close();
} else {
message = "Database still exists.";
}
} catch (e) {
message = "Failed delete at path:" + path + ": Error is: " + e.message;
}
}
}
The following quick example in TypeScript shows a way to get typed refs without using inline (which are suppose to be bad for performance). It is however rather ugly having to define two variables (refAnimationWrapper and refAnimationWrapperHandler) to define one ref. Does anyone have a simpler solution, could #decorators maybe be a solution?
https://www.typescriptlang.org/docs/handbook/decorators.html
import * as React from 'react';
import {TweenMax} from 'gsap';
export class TransitionDummy extends React.Component<any, any> {
private transitionDuration = 0.4;
private refAnimationWrapper:HTMLDivElement;
private refAnimationWrapperHandler = (ref:HTMLDivElement) => this.refAnimationWrapper = ref;
constructor(props) {
super(props);
}
public componentWillEnter(done) {
TweenMax.fromTo(this.refAnimationWrapper, this.transitionDuration, {opacity: 0}, {opacity: 1, onComplete: done});
}
public componentWillLeave(done) {
TweenMax.to(this.refAnimationWrapper, this.transitionDuration, {opacity: 0, onComplete: done});
}
public render() {
return (
<div ref={this.refAnimationWrapperHandler}>
{this.props.children}
</div>
);
}
}
You can wrap both of them in a class, that way each ref has one member:
class RefedElement<T> {
wrapper: T;
handler = (ref: T) => this.wrapper = ref;
}
export class TransitionDummy extends React.Component<any, any> {
private transitionDuration = 0.4;
private refAnimation: RefedElement<HTMLDivElement>;
constructor(props) {
super(props);
this.refAnimation = new RefedElement<HTMLDivElement>();
}
public componentWillEnter(done) {
TweenMax.fromTo(this.refAnimation.wrapper, this.transitionDuration, {opacity: 0}, {opacity: 1, onComplete: done});
}
public componentWillLeave(done) {
TweenMax.to(this.refAnimation.wrapper, this.transitionDuration, {opacity: 0, onComplete: done});
}
public render() {
return (
<div ref={ this.refAnimation.handler }>
{this.props.children}
</div>
);
}
}