0x58
0x58

Reputation: 427

Call FutureBuilder from RaisedButton

i would love to call the Future fetchPost from a RaisedButton or in other words i don't wan't the FutureBuilder to do anything until i click the button, i tried calling fetchPost from the button but it won't work and I'm stuck.

PS: I used the example from this page https://flutter.io/cookbook/networking/fetch-data/

Your help is appreciated.

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Post> fetchPost() async {
  final response =
  await http.get('https://jsonplaceholder.typicode.com/posts/1');

  if (response.statusCode == 200) {
    // If the call to the server was successful, parse the JSON
    return Post.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}

class Post {
  final int userId;
  final int id;
  final String title;
  final String body;

  Post({this.userId, this.id, this.title, this.body});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
      body: json['body'],
    );
  }
}

class FirstFragment extends StatelessWidget {
  FirstFragment(this.usertype,this.username);
  final String usertype;
  final String username;

  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    final Size screenSize = MediaQuery.of(context).size;

    return new SingleChildScrollView(
      padding: new EdgeInsets.all(5.0),
      child: new Padding(
        padding: new EdgeInsets.symmetric(vertical: 0.0, horizontal: 0.0),
        child: new Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Container(
              child: new RaisedButton(
                child: new Text('Call'),
                onPressed: (){
                  fetchPost();
                },
              ),
            ),
            new Container(
              child: FutureBuilder<Post>(
                future: fetchPost(),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Text(snapshot.data.title);
                  } else if (snapshot.hasError) {
                    return Text("${snapshot.error}");
                  }
                  // By default, show a loading spinner
                  return CircularProgressIndicator();
                },
              )
            )
          ],
        ),
      ),
    );

  }
}

Upvotes: 1

Views: 4198

Answers (2)

goops17
goops17

Reputation: 1160

As Dhiraj explained above calling fetchPost alone won't change UI, so you need to reset UI by calling setState.

Below is how your code should look like

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Post> fetchPost() async {
  final response =
  await http.get('https://jsonplaceholder.typicode.com/posts/1');

  if (response.statusCode == 200) {
    // If the call to the server was successful, parse the JSON
    return Post.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}

class Post {
  final int userId;
  final int id;
  final String title;
  final String body;

  Post({this.userId, this.id, this.title, this.body});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
      body: json['body'],
    );
  }
}

class FirstFragment extends StatefulWidget {
  FirstFragment(this.usertype,this.username);
  final String usertype;
  final String username;
  @override
  _FirstFragmentState createState() => new _FirstFragmentState(usertype, username);
}
class _FirstFragmentState extends State<FirstFragment> {
  _FirstFragmentState(this.usertype,this.username);
  final String usertype;
  final String username;
  @override
  Widget build(BuildContext context) {
    final ThemeData theme = Theme.of(context);
    final Size screenSize = MediaQuery.of(context).size;

    return new SingleChildScrollView(
      padding: new EdgeInsets.all(5.0),
      child: new Padding(
        padding: new EdgeInsets.symmetric(vertical: 0.0, horizontal: 0.0),
        child: new Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Container(
              child: new RaisedButton(
                child: new Text('Call'),
                onPressed: (){
                  fetchPost();
                  setState(() {          
                  });
                },
              ),
            ),
            new Container(
              child: FutureBuilder<Post>(
                future: fetchPost(),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Text(snapshot.data.title);
                  } else if (snapshot.hasError) {
                    return Text("${snapshot.error}");
                  }
                  // By default, show a loading spinner
                  return CircularProgressIndicator();
                },
              )
            )
          ],
        ),
      ),
    );

  }
}

Upvotes: 2

Dhiraj Sharma
Dhiraj Sharma

Reputation: 4859

Calling fetchPost alone wont do changes in UI.

At first inside build your futurebuilder is execcuted which gets data from fetchPost.

Further then to fetchPost agiain you need to rebuild.

To do so inside onPressed of raised button:

onPressed: (){
               setState((){})
             },

And to fetch post only on button click (not for first time) you should use then()

Details here : https://www.dartlang.org/tutorials/language/futures

Upvotes: 2

Related Questions