Renis
Renis

Reputation: 43

The method 'map' was called on null. & Tried calling: map<Answer>(Closure: (String) => Answer)

Error:

The following NoSuchMethodError was thrown building MyApp(dirty, state: _MyAppState#ad714):

  The method 'map' was called on null.
  Receiver: null
  Tried calling: map<Answer>(Closure: (String) => Answer)

my code:

import 'package:flutter/material.dart';


import './qestion.dart';
import 'answer.dart';

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



class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {
  var _questionIndex = 0;

  void _answerQuestion() {
    setState(() {
      _questionIndex = _questionIndex + 1;
    });
    print(_questionIndex);
    //print('Answer choosen');
  }

  Widget build(BuildContext context) {
    var questions = [
      {
        'questionText': 'what\'s your favorite color?',
        'answers': ['red', 'black', 'brown'],
      },
      {
        'questionText': 'what\s your favorite animal ?',
        'answers': ['lion', 'horse'],
      },
    ];

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('My First Application'),
        ),
        body: Column(
          children: [
            Question(
              questions[_questionIndex]['questionText'],
            ),

            ...(questions[_questionIndex]['answer'] as List<String>)
                    . map((answer) {
                  return Answer(_answerQuestion, answer);
                }).toList() 
                [],
            // RaisedButton(
            //   child: Text('Answer 2'),
            //   onPressed: () => {print('it is a =anonymus ans')},
            // ),
          ],
        ),
      ),
    );
  }
}

Problematic part may be:

        ...(questions[_questionIndex]['answer'] as List<String>)
                . map((answer) {
              return Answer(_answerQuestion, answer);
            }).toList() 

Question.dart:

import 'package:flutter/material.dart';

class Question extends StatelessWidget {
  // const Question({ Key? key }) : super(key: key);
  final String questionText;
  Question(this.questionText);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(10),
      width: double.infinity,
      child: Text(
        questionText,
        style: TextStyle(fontSize: 25),
        textAlign: TextAlign.center,
      ),
    );
  }
}

Answer.dart

import 'package:flutter/material.dart';

class Answer extends StatelessWidget {
  //const Answer({ Key? key }) : super(key: key);
  final Function selectHandler;
  final String answerText;
  Answer(this.selectHandler, this.answerText);

  @override
  Widget build(BuildContext context) {
    return Container(
        width: double.infinity,
        child: RaisedButton(
          textColor: Colors.black,
          color: Colors.cyan,
          child: Text(answerText),
          onPressed: selectHandler,
        ));
  }
}

how can i solve this error in VScode editor?

Upvotes: 4

Views: 453

Answers (2)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63604

Let's talk about the main part, to generate Answer widgets.

questions[_questionIndex]['answers'] provides us the answers per question. and by mapping this we can generate the List<Answer> widgets. It will be long expression to handle(for me and failed), therefore I am using inline function to generate Answer widgets.

...() {
  final List<String?>? answers =
      questions[_questionIndex]['answers'] as List<String?>?;

  return answers == null
      ? [
          Text("could not find any answer"),
        ]
      : answers
          .map(
            (e) => Answer(
              selectHandler: _answerQuestion,
              answerText: e ?? "failed to get answer",
            ),
          )
          .toList();
}()

Another common issue is

Fuction can't be assing....void Function....

We can simply use VoidCallback instead of Function, else we need to use anonymous function to handle this.

Small issue like adding @override, moving data to widget level, key constructor fixed on full snippet, and I prefer and suggest using named Constructor. You can search and learn more about those keywords.

Remember to handle range error and page navigation, I stop the _questionIndex increment on end of list.

Run on dartPad

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {
  var _questionIndex = 0;
  var questions = [
    {
      'questionText': 'what\'s your favorite color?',
      'answers': ['red', 'black', 'brown'],
    },
    {
      'questionText': 'what\s your favorite animal ?',
      'answers': ['lion', 'horse'],
    },
    {
      'questionText': 'what\s your favorite animal ?',
    },
  ];
  void _answerQuestion() {
    setState(() {
      /// handle range error,
      if (_questionIndex < questions.length - 1) {
        _questionIndex += 1;
      }
    });
    print(_questionIndex);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('My First Application'),
        ),
        body: Column(
          children: [
            Question(
              questionText: questions[_questionIndex]['questionText'] as String,
            ),
            ...() {
              final List<String?>? answers =
                  questions[_questionIndex]['answers'] as List<String?>?;

              return answers == null
                  ? [
                      Text("could not find any answer"),
                    ]
                  : answers
                      .map(
                        (e) => Answer(
                          selectHandler: _answerQuestion,
                          answerText: e ?? "failed to get answer",
                        ),
                      )
                      .toList();
            }()
          ],
        ),
      ),
    );
  }
}

class Question extends StatelessWidget {
  // const Question({ Key? key }) : super(key: key);
  final String questionText;
  const Question({
    Key? key,
    required this.questionText,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(10),
      width: double.infinity,
      child: Text(
        questionText,
        style: const TextStyle(fontSize: 25),
        textAlign: TextAlign.center,
      ),
    );
  }
}

class Answer extends StatelessWidget {
  final VoidCallback selectHandler;
  final String answerText;

  const Answer({
    Key? key,
    required this.selectHandler,
    required this.answerText,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
        width: double.infinity,
        child: ElevatedButton(
          child: Text(answerText),
          onPressed: selectHandler,
        ));
  }
}

Upvotes: 1

Kshitij Dhakal
Kshitij Dhakal

Reputation: 844

You have typo. In place where you declare variable there is answers field, but you are accessing answer field.

Change following line and see again.

...(questions[_questionIndex]['answers'] as List<String>)
                    . map((answer) {
                  return Answer(_answerQuestion, answer);
                }).toList()

Upvotes: 1

Related Questions