I am programming a flutter app and have written dart class.
When I call the classes constructor, I the following error at runtime...
error: Instance field access outside constructor
The class looks as follows...
import '../framework/server.dart';
import 'package:meta/meta.dart';
class GamesRequestMessage extends Message {
String getName() => "GamesRequestMessage";
String idToken;
GamesRequestMessage({ #required this.idToken = idToken });
JsonObject content()
{
JsonObject content = JsonObject();
content.writeString("idToken" , idToken);
}
}
And the calling code where the error occurs is as follows...
var msg = GamesRequestMessage (idToken : idToken.token);
What has gone wrong? Also, why is this error not a compilation time error?
this.idToken = idToken should be just this.idToken
Related
I'm getting an error like
The expression doesn't evaluate to a function, so it can't be invoked.
Is there any workaround to achieve this I have different classes being returned from a map according to the key.
void main() {
Map<String, Type> map = {'user': User};
Type T = map['user']!;
User a = T(5);
print(a.id);
}
class User {
User(this.id);
final int id;
}
In the excellent Flutter book by Raywenderlich, Chapter 13 is dedicated to obtaining Responses from an api using libraries Chopper and JsonConverter.
The code in Github is here
He also proposes the use of a response wrapper like functional programming, of the type Success/Error.
The ModelConverter from Response to Success/Error wrapper, applies to the APIRecipeQuery model and only uses one method in one line final recipeQuery = APIRecipeQuery.fromJson(mapData);. It seems quite logical to make a generic convert, since it is a very useful class.
import 'dart:convert';
import 'package:chopper/chopper.dart';
import 'model_response.dart';
import 'recipe_model.dart';
class ModelConverter implements Converter {
#override
Request convertRequest(Request request) {
// Add a header to the request that says you have a request type of application/json using jsonHeaders.
// These constants are part of Chopper.
final req = applyHeader(
request,
contentTypeKey,
jsonHeaders,
override: false,
);
return encodeJson(req);
}
#override
Response<BodyType> convertResponse<BodyType, InnerType>(Response response) {
return decodeJson<BodyType, InnerType>(response);
}
Request encodeJson(Request request) {
final contentType = request.headers[contentTypeKey];
// Confirm contentType is of type application/json.
if (contentType != null && contentType.contains(jsonHeaders)) {
return request.copyWith(body: json.encode(request.body));
}
return request;
}
Response decodeJson<BodyType, InnerType>(Response response) {
final contentType = response.headers[contentTypeKey];
var body = response.body;
if (contentType != null && contentType.contains(jsonHeaders)) {
body = utf8.decode(response.bodyBytes);
}
try {
final mapData = json.decode(body);
if (mapData['status'] != null) {
return response.copyWith<BodyType>(
body: Error(Exception(mapData['status'])) as BodyType);
}
/*
The only line is next
*/
final recipeQuery = APIRecipeQuery.fromJson(mapData);
return response.copyWith<BodyType>(
body: Success(recipeQuery) as BodyType);
} catch (e) {
chopperLogger.warning(e);
return response.copyWith<BodyType>(body: Error(e) as BodyType);
}
}
So, I have tried by passing the model in the constructor as a parameter:
class ModelConverter <T extends JsonConverter> implements Converter {
final T model;
ModelConverter ({#required this.model});
and
I invoke it in recipe_service.dart with converter: ModelConverter(model: APIRecipeQuery), but I don't know how to reference the model statically, and can't access the method model.fromJson
Next, I have tried passing just the function converter:
class ModelConverter implements Converter {
Function fromJson;
ModelConverter ({# required this.fromJson});
with a getter in the API, and in recipe_service.dart with converter: ModelConverter(fromJson: APIRecipeQuery.fjConverter)
class APIRecipeQuery {
static Function get fjConverter => _ $ APIRecipeQueryFromJson;
But I can't get it to work.
What would be the best approach to make the ModelConverter generic?
Thnks in advance.
Solved in this post
model_converter.dart
. . .
typedef CreateModelFromJson = dynamic Function(Map<String, dynamic> json);
class ModelConverter<Model> implements Converter {
final CreateModelFromJson fromJson;
ModelConverter({#required this.fromJson});
. . .
final query = fromJson(mapData) as Model;
. . .
and recipe_service.dart
. . .
converter: ModelConverter<APIRecipeQuery>(
fromJson: (json) => APIRecipeQuery.fromJson(json),
),
. . .
Here is my class:
class WorldTimeClass {
String flag;
String url;
String time;
String location;
WorldTimeClass({this.flag, this.url, this.time, this.location});
Future<String> getData() async {
try{
Response load = await get('http://worldtimeapi.org/api/timezone/$url');
Map x(){if(load.statusCode == 200){
print(load.statusCode);
Map map = jsonDecode(load.body);
return map;}
else{
print('No Access');
return {1:'NoAccess.'};}
}
Map myMap = x();
String datetime = myMap['utc_datetime'];
String offsetUTC = myMap['utc_offset'];
DateTime dateTimeObjectConvert = DateTime.parse(datetime);
// Below converts the datetime string to a DateTime Object and then converts the UTC Offset to a substring only '01' out of +01:00 and then converts it to an int Object and then adds it to the DateTime Object as a Duration (hours);
dateTimeObjectConvert = dateTimeObjectConvert.add(Duration(hours: int.parse(offsetUTC.substring(1,3))));
return time = dateTimeObjectConvert.toString();
}
catch(e,s){
return 'Could not access time data from API.\nWe are sorry, please try again.\nError occured: $e';
}
}
var myString = getData().then((value) => value);
DateFormat pretty = DateFormat().add_jm().format(myString);
}
How can I access myString and execute it inside my class in order to use the resulting String object to use it inside a second method pretty ?
Also, I need to understand what does the below exception mean?
Only static members can be accessed in initializers.
Only static members can be accessed in initializers.
This basically means that you cannot call methods of a class or access properties of a specific class directly under class declaration.
You are getting the error on those two lines:
var myString = getData().then((value) => value);
DateFormat pretty = DateFormat().add_jm().format(myString);
Therefore create a method that returns a String then all you have to do is to call that method and it will give you the String, and add the code above inside the method:
String getDateFormat(){
var myString = getData().then((value) => value);
return DateFormat().add_jm().format(myString);
}
To access your myString variable you'll have to do one of those things:
Instantiate an WorldTimeClass object and access it using yourWorldClassObject.myString
Make it into in static member by using the static keyword like static var myString. This is what " Only static members can be accessed in initializers. " is all about. You have to create an instance of the class if you want to access it's properties, or make them static to access them without the need to instantiate an object. Simply WorldTimeClass.myString.
I'm trying to make all strings in 1 file, but when I try it it produces an error Only static members can be accessed in initializers
I want to put all strings in 1 file and can be called with the getter method for all classes, be it an ordinary class, a class with StatefullWidget, and a class with StatelessWidget
error Only static members can be accessed in initializers leading to configStrings in the ApiService class
My Code in config_string.dart
class ConfigStrings {
String _blogUrl = "https://blogspot-to-app.blogspot.com/";
String get blogUrl => _blogUrl;
}
My Code in api_service.dart
import 'package:blogspot/config/config_strings.dart';
import 'package:http/http.dart';
class ApiServices {
var configStrings = ConfigStrings();
final String baseUrl = configStrings.blogUrl;
Client client = Client();
}
You need to access configStrings inside a method or the constructor:
import 'package:blogspot/config/config_strings.dart';
import 'package:http/http.dart';
class ApiServices {
var configStrings = ConfigStrings();
ApiServices(){
final String baseUrl = configStrings.blogUrl;
}
Client client = Client();
}
I have API communication service in my Flutter app with 10+ different services, and 100+ API calls that heed to parse data. In order to reuse code I've decided to create some common parsing code that is going to parse data from API:
ApiResponse handleObjectResponse({
#required http.Response serverResponse,
#required Function objectConstructor,
}) {
if (serverResponse.statusCode == 200) {
dynamic responseObject = objectConstructor(json.decode(serverResponse.body));
return ApiResponse(responseObject: responseObject);
} else {
ApiError error = responseHasError(serverResponse.body);
return ApiResponse(error: error);
}
}
This way I am able to parse JSON object from API in a reusable way no matter what the Object class is, just by passing constructor function to this method.
When I call this method in any of the Services I've created for fetching data like this:
handleObjectResponse(serverResponse: response, objectConstructor: ChartData.fromJson);
I get error: The getter 'fromJson' isn't defined for the class 'ChartData'.
Try importing the library that defines 'fromJson', correcting the name to the name of an existing getter, or defining a getter or field named 'fromJson'.
Where I think the problem is is in this model class and factory statement, but I don't know how to fix it:
class ChartData {
List<ChartDataPoint> points;
ChartData({
this.points,
});
factory ChartData.fromJson(Map<String, dynamic> json) {
List jsonPoints = json["data"];
return ChartData(
points: List.generate(jsonPoints.length,
(i) => ChartDataPoint.fromJsonArray(jsonPoints[i])));
}
}
You cannot pass constructors as functions. You need to create a function what will call the constructor instead:
(int a) => Foo(a);
Just a 2022 update: since 2.15 it's possible by Class.new, see the complete issue: https://github.com/dart-lang/language/issues/216.
class A {
final String a;
const A(this.a);
#override
String toString() => 'A($a)';
}
class B {
final String b;
const B(this.b);
#override
String toString() => 'B($b)';
}
void main() {
final List<Object Function(String)> constructors = [A.new, B.new];
for (final Object Function(String) constructor in constructors) {
final Object instance = constructor('My Constructor Parameter');
if (instance is A) {
print(instance.toString());
}
}
}
Note that if you're using named params, both class constructors must have the same param name, otherwise the constructor signatures won't match and then it will generate this static error:
The element type X can't be assigned to the list type Y.