Search code examples
flutterdartnosuchmethod

Flutter, NoSuchMethod: The getter 'notes' was called on null


I'm learning flutter and trying to make a notes app and hardcode 3 notes using inherited widget and a list of map. Problem is that I get thrown this error when I try to run the app so far: I/flutter (32083): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ I/flutter (32083): The following NoSuchMethodError was thrown building HomeScreen(dirty, state: I/flutter (32083): _HomeScreenState#050b1): I/flutter (32083): The getter 'notes' was called on null. I/flutter (32083): Receiver: null I/flutter (32083): Tried calling: notes I/flutter (32083):

This is the code so far:

main.dart:

import 'package:flutter/material.dart';

import 'home_screen.dart';
import 'note_inherited_widget.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return NoteInheritedWidget(
          MaterialApp(
        home: HomeScreen(),
        theme: ThemeData(
            primaryColor: Colors.deepOrange, accentColor: Colors.deepPurple),
      ),
    );
  }
}

home_screen.dart

import 'package:flutter/material.dart';
import 'package:simple_notes/note_inherited_widget.dart';

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final myController = TextEditingController();

  @override
  void dispose() {
    // Clean up the controller when the widget is disposed.
    myController.dispose();
    super.dispose();
  }

  List<Map<String, String>> get notes => NoteInheritedWidget.of(context).notes;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Simple Notes'),
          centerTitle: true,
        ),
        body: ListView.builder(itemBuilder: (context, index) {
          return Card(
            child: Column(
              children: <Widget>[
                NoteTitle(notes[index]['title']), 
                NoteText(notes[index]['text'])],
            ),
          );
        },
        itemCount: notes.length,
        ),
        bottomNavigationBar: (FlatButton(
            onPressed: () {
              showMyDialog(context);
            },
            child: Text('Add note'))));
  }

  Future<void> showMyDialog(
    BuildContext context,
  ) {
    return showDialog<void>(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            content: TextField(),
            actions: <Widget>[
              new FlatButton(
                  onPressed: () => Navigator.pop(context), child: Text('Save'))
            ],
          );
        });
  }
}

class NoteTitle extends StatelessWidget {
  final String title;

  NoteTitle(this.title);

  @override
  Widget build(BuildContext context) {
    return Text(
      title,
      style: TextStyle(
        fontSize: 25,
        fontWeight: FontWeight.bold
      ),
    );
  }
}

class NoteText extends StatelessWidget {
  final String text;

  NoteText(this.text);

  @override
  Widget build(BuildContext context) {
    return Text(
      text,
      style: TextStyle(
        color: Colors.grey.shade600,
      ),
      maxLines: 2,
      overflow: TextOverflow.ellipsis,
    );
  }
}

note_inherited_widget.dart

import 'package:flutter/material.dart';

class NoteInheritedWidget extends InheritedWidget {

  final notes = [
    {
      'title': 'My first title',
      'text': 'My first text'
    },
    {
      'title': 'My second title',
      'text': 'My second  text'
    },
    {
      'title': 'My third title',
      'text': 'My third text'
    }
  ];

  NoteInheritedWidget(Widget child) : super(child: child);

bool updateShouldNotify(NoteInheritedWidget oldwidget) => oldwidget.notes != notes;

  static NoteInheritedWidget of(BuildContext context) =>
    context.dependOnInheritedWidgetOfExactType(aspect: NoteInheritedWidget) as NoteInheritedWidget;
}

I also had problems trying to implement the inherited widget method, I think there might be mistakes there that I dont understand. So if any of you guys could help me with this that would be terrific. @{11488366}

Thank you in advance!


Solution

  • I guess you need to make a separation, make a dummy data class like this :

    class DummyDataProvider{
    
    final notes = [
        {
          'title': 'My first title',
          'text': 'My first text'
        },
        {
          'title': 'My second title',
          'text': 'My second  text'
        },
        {
          'title': 'My third title',
          'text': 'My third text'
        }
      ];
     } 
    

    And make an instance of this class inside your widget which extends InheritedWidget so you can provide the same instance using InheritedWidget.

    class NoteInheritedWidget extends InheritedWidget {
    
      final dummyData = DummyDataProvider();
    
      NoteInheritedWidget(Widget child) : super(child: child);
    
    
     @override
      bool updateShouldNotify(NoteInheritedWidget old) => dummyData != old.dummyData ;
    
      static DummyDataProvider of(BuildContext context) =>
        context.dependOnInheritedWidgetOfExactType<NoteInheritedWidget>().dummyData;
    }
    

    And don't forget to remove this line of code :

    List<Map<String, String>> get notes => NoteInheritedWidget.of(context).notes;
    

    And replace it with this and call of method inside didChangeDependinces method as the context is ready to use in this method :

     DummyDataProvider notes;
    
         @override
         void didChangeDependencies()
         {
         super.didChangeDependencies();
         notes = NoteInheritedWidget.of(context);
         }
    

    Or you can call it in the build method.

    Feel free to check dependOnInheritedWidgetOfExactType docs from here