MessagePopover does not show any items - sapui5

I have downloaded the example Message Popover from https://sapui5.hana.ondemand.com/#/entity/sap.m.MessagePopover/sample/sap.m.sample.MessagePopover/code/view/MessagePopover.view.xml and have modified property binding to named model as follows:
oMessagePopover = new MessagePopover({
items: {
path: 'Message>/',
template: oMessageTemplate
},
activeTitlePress: function () {
MessageToast.show('Active title is pressed');
}
});
and the model definition:
this.getView().setModel(new JSONModel(aMockMessages), "Message");
it shows item with empty values:
it should be
What am I doing wrong?
Here is the whole code:
sap.ui.define([
'sap/m/MessagePopover',
'sap/m/MessageItem',
'sap/m/MessageToast',
'sap/m/Link',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
], function (MessagePopover, MessageItem, MessageToast, Link, Controller, JSONModel) {
"use strict";
var oMessagePopover;
return Controller.extend("sap.m.sample.MessagePopover.controller.MessagePopover", {
onInit: function () {
// create any data and a model and set it to the view
var oLink = new Link({
text: "Show more information",
href: "http://sap.com",
target: "_blank"
});
var oMessageTemplate = new MessageItem({
type: '{type}',
title: '{title}',
activeTitle: "{active}",
description: '{description}',
subtitle: '{subtitle}',
counter: '{counter}',
link: oLink
});
var sErrorDescription = 'First Error message description. \n' +
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod' +
'tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,' +
'quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo' +
'consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse' +
'cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non' +
'proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
/* oMessagePopover = new MessagePopover({
items: {
path: '/',
template: oMessageTemplate
},
activeTitlePress: function () {
MessageToast.show('Active title is pressed');
}
});*/
oMessagePopover = new MessagePopover({
items: {
path: 'Message>/',
template: oMessageTemplate
},
activeTitlePress: function () {
MessageToast.show('Active title is pressed');
}
});
var aMockMessages = [{
type: 'Error',
title: 'Error message',
active: true,
description: sErrorDescription,
subtitle: 'Example of subtitle',
counter: 1
}, {
type: 'Warning',
title: 'Warning without description',
description: ''
}, {
type: 'Success',
title: 'Success message',
description: 'First Success message description',
subtitle: 'Example of subtitle',
counter: 1
}, {
type: 'Error',
title: 'Error message',
description: 'Second Error message description',
subtitle: 'Example of subtitle',
counter: 2
}, {
type: 'Information',
title: 'Information message',
description: 'First Information message description',
subtitle: 'Example of subtitle',
counter: 1
}];
this.getView().setModel(new JSONModel(aMockMessages), "Message");
//this.getView().setModel(new JSONModel(aMockMessages));
this.byId("messagePopoverBtn").addDependent(oMessagePopover);
},
// Display the button type according to the message with the highest severity
// The priority of the message types are as follows: Error > Warning > Success > Info
buttonTypeFormatter: function () {
var sHighestSeverityIcon;
var aMessages = this.getView().getModel().oData;
aMessages.forEach(function (sMessage) {
switch (sMessage.type) {
case "Error":
sHighestSeverityIcon = "Negative";
break;
case "Warning":
sHighestSeverityIcon = sHighestSeverityIcon !== "Negative" ? "Critical" : sHighestSeverityIcon;
break;
case "Success":
sHighestSeverityIcon = sHighestSeverityIcon !== "Negative" && sHighestSeverityIcon !== "Critical" ? "Success" :
sHighestSeverityIcon;
break;
default:
sHighestSeverityIcon = !sHighestSeverityIcon ? "Neutral" : sHighestSeverityIcon;
break;
}
});
return sHighestSeverityIcon;
},
// Display the number of messages with the highest severity
highestSeverityMessages: function () {
var sHighestSeverityIconType = this.buttonTypeFormatter();
var sHighestSeverityMessageType;
switch (sHighestSeverityIconType) {
case "Negative":
sHighestSeverityMessageType = "Error";
break;
case "Critical":
sHighestSeverityMessageType = "Warning";
break;
case "Success":
sHighestSeverityMessageType = "Success";
break;
default:
sHighestSeverityMessageType = !sHighestSeverityMessageType ? "Information" : sHighestSeverityMessageType;
break;
}
return this.getView().getModel().oData.reduce(function (iNumberOfMessages, oMessageItem) {
return oMessageItem.type === sHighestSeverityMessageType ? ++iNumberOfMessages : iNumberOfMessages;
}, 0);
},
// Set the button icon according to the message with the highest severity
buttonIconFormatter: function () {
var sIcon;
var aMessages = this.getView().getModel().oData;
aMessages.forEach(function (sMessage) {
switch (sMessage.type) {
case "Error":
sIcon = "sap-icon://error";
break;
case "Warning":
sIcon = sIcon !== "sap-icon://error" ? "sap-icon://alert" : sIcon;
break;
case "Success":
sIcon = "sap-icon://error" && sIcon !== "sap-icon://alert" ? "sap-icon://sys-enter-2" : sIcon;
break;
default:
sIcon = !sIcon ? "sap-icon://information" : sIcon;
break;
}
});
return sIcon;
},
handleMessagePopoverPress: function (oEvent) {
oMessagePopover.toggle(oEvent.getSource());
}
});
});

In your MessageItem you should bind your attributes to the right model:
var oMessageTemplate = new MessageItem({
type: '{Message>type}',
title: '{Message>title}',
activeTitle: "{Message>active}",
description: '{Message>description}',
subtitle: '{Message>subtitle}',
counter: '{Message>counter}',
link: oLink
});
or another solution is to set this JSON model as default this.getView().setModel(new JSONModel(aMockMessages));

Related

Flutter type "null" is not a sub-type of type "string"

I'm trying to load some data from a json file called recipe.json from my assets folder. The model that I've written is :
class RecipeModel {
final String id;
final String name;
final String videoLink;
final String author;
final String category;
final String time;
RecipeModel({
required this.id,
required this.name,
required this.videoLink,
required this.author,
required this.category,
required this.time,
});
factory RecipeModel.fromJson(Map<String, dynamic> json) {
return RecipeModel(
id: json['id'],
name: json['name'],
videoLink: json['videoLink'],
author: json['author'],
category: json['category'],
time: json['time'],
);
}
}
And the function that fetches the data:
Future _getRecipeData() async {
// var response = await http.get(
// Uri.https("jsonplaceholder.typicode.com", 'users'),
// );
String response = await DefaultAssetBundle.of(context)
.loadString('assets/json/recipe.json');
var result = json.decode(response);
List<RecipeModel> recipes = [];
for (var i in result) {
RecipeModel recipe = RecipeModel(
id: i['id'],
name: i['name'],
videoLink: i['videoLink'],
author: i['author'],
category: i['category'],
time: i['time'],
);
recipes.add(recipe);
}
print(recipes.length);
}
And I'm loading the data when the page loads:
#override
void initState() {
super.initState();
_getRecipeData();
}
But I get an error which says: Unhandled Exception: type 'Null' is not a subtype of type 'String'. Is there something that I'm missing?
Edit 1:
here's my recipe.json file:
[
{
"_id": "1",
"name": "Kacchi Biriyani",
"videoLink": "PQSagzssvUQ",
"author": "Alan Ford",
"category":"Biriyani",
"time": "15 min",
"steps": {
"step 1": "lorel ipsum dolor",
"step 2": "lorel ipsum dolor",
"step 3": "lorel ipsum dolor",
"step 4": "lorel ipsum dolor"
}
},
{
"_id": "2",
"name": "Mughal Biriyani",
"videoLink": "PQSagzssvUQ",
"author": "Ricky James",
"category":"Biriyani",
"time": "10 min",
"steps": {
"step 1": "lorel ipsum dolor",
"step 2": "lorel ipsum dolor",
"step 3": "lorel ipsum dolor",
"step 4": "lorel ipsum dolor"
}
}
]
Update 1:
List<RecipeModel> _recipes = [];
Future _getRecipeData() async {
// var response = await http.get(
// Uri.https("jsonplaceholder.typicode.com", 'users'),
// );
String response = await DefaultAssetBundle.of(context)
.loadString('assets/json/recipe.json');
var data = json.decode(response);
for (var i in data) {
RecipeModel recipe = RecipeModel(
id: i['id'],
name: i['name'],
videoLink: i['videoLink'],
author: i['author'],
category: i['category'],
time: i['time'],
);
_recipes.add(recipe);
}
print(_recipes);
}
#override
void initState() {
super.initState();
_getRecipeData();
print(_recipes);
}
in your fromJson and _getRecipeData your are accessing id like json['id'] and i['id']
however in your data it is _id there is underscore missing.
you can use null operator to avoid nulls also like this
RecipeModel recipe = RecipeModel(
id: i['id'] ?? "",
name: i['name'] ?? "",
videoLink: i['videoLink'] ?? "",
author: i['author'] ?? "",
category: i['category'] ?? "",
time: i['time'] ?? "",
);

Graphql_flutter mutation running on playground doesn't work on running device/emulator

During my project development, I'm using flutter with graphql, for testing purpose tried mutation on playground and passed the test, but on device and emulator getting error response with 5xx, I know this is "server side" error but tested same mutation from our webpage and it is working too.
Beside with flutter, I am using following packages:
equatable: ^1.2.5
gql: ^0.12.4
graphql: ^4.0.0
graphql_flutter: ^4.0.1
json_annotation: ^3.1.1
meta: ^1.3.0
artemis: ^6.18.4
build_runner: ^1.11.1
json_serializable: ^3.5.1
Till now on this project, I run almost 10 mutations successfully with this file syntax:
myproject/
graphql/
queries/
register.graphql -> running well
createOffer.graphql -> getting 500 error
schema.graphql
lib/
models/
...generatedModels here..
views/
register.dart
createOffer.dart
register.graphql
mutation signUp(
$company_name:String!,
$email: String!,
$firstname: String!,
$lastname: String!,
$phone: String!,
$tin_ein_number: String!,
) {
createShipperUser(
company_name: $company_name,
email: $email,
firstname: $firstname,
lastname: $lastname,
phone: $phone,
tin_ein_number: $tin_ein_number,
) {
id
}
}
register.dart
Widget buildFormBody(BuildContext context) {
return Mutation(
options: MutationOptions(
document: SignUpMutation().document,
onCompleted: (dynamic resultData) {
if (resultData != null) {
onRegistered();
}
},
if (e.linkException != null) {
showSnackbar(context,
'Something went wrong, please check your network connection and try again.');
return;
}
final validationErrors = findValidationErrors(
e.graphqlErrors,
[
'firstname',
'lastname',
'email',
'phone',
'tin_ein_number',
'company_name',
],
);
if (validationErrors.isNotEmpty) {
setState(() {
firstnameError = validationErrors['firstname'];
surnameError = validationErrors['lastname'];
emailError = validationErrors['email'];
phoneError = validationErrors['phone'];
if (isTin) {
einError = null;
tinError = validationErrors['tin_ein_number'];
} else {
einError = validationErrors['tin_ein_number'];
tinError = null;
}
companyError = validationErrors['company_name'];
});
//TODO text
showSnackbar(context, 'Please check entered fields');
} else if (e.graphqlErrors.isNotEmpty) {
showSnackbar(
context, e.graphqlErrors[0].message ?? 'Something went wrong');
} else {
showSnackbar(context, 'Something went wrong');
}
builder: (runMutation, result) {
isLoading = result.isLoading;
return Form(
ElevatedButton(
onPressed: () => onSubmitTap(runMutation),
child: Text(
'Submit',
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.w700),
),
)
);
void onSubmitTap(RunMutation runMutation) {
hideKeyboard();
if (isLoading) {
return;
}
if (formKey.currentState.validate()) {
formKey.currentState.save();
setState(() {
savedPhone = getPhoneMask(savedPhone);
});
runMutation(SignUpArguments(
company_name: savedCompany,
email: savedEmail,
phone: savedPhone,
tin_ein_number: isTin ? 'tin_$savedTin' : 'ein_$savedEin',
firstname: savedFirstname,
lastname: savedSurname,
).toJson());
}
}
And following are mutation getting 500 error.
createOffer.graphql
Mutation(
options: MutationOptions(
document: CreateShipmentMutation().document,
errorPolicy: ErrorPolicy.all,
update: (GraphQLDataProxy cache, QueryResult result) {
if (result.hasException) {
print(result.exception);
}
},
onCompleted: (dynamic resultData) {
if (resultData != null) {
print('completed');
print(resultData);
// onCreated();
}
},
onError: (e) {
if (e.linkException != null) {
showSnackbar(context,
'Something went wrong, please check your network connection and try again.');
return;
}
if (e.graphqlErrors.isNotEmpty) {
debugPrint(e.graphqlErrors.toString(),
wrapWidth: 1024);
} else {
showSnackbar(context, 'Something went wrong');
}
},
),
builder: (runMutation, result) {
isLoading = result.isLoading;
return Card(
child: ElevatedButton(
onPressed: () => onReviewTap(runMutation),
style: ElevatedButton.styleFrom(
padding:
EdgeInsets.symmetric(vertical: 14)),
child: AnimatedSwitcher(
duration: Duration(milliseconds: 150),
child: result.isLoading
? Theme(
data: Theme.of(context).copyWith(
accentColor: Colors.white),
child:
const ProgressIndicatorSmall(),
)
: Text(
'Review Shipment',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700),
),
),
),
);
void onReviewTap(RunMutation runMutation) {
final acces = accessories
.map((accessory) {
if (accessory.isChecked) {
return accessory.enumType;
}
})
.where((element) => element != null)
.toList();
final stops = isMultipleStops ? items : p2pitems;
hideKeyboard();
if (isLoading) {
return;
}
runMutation(CreateShipmentArguments(
input: OfferInput(
openPrice: 30,
shipment: CreateShipmentInput(
requestedTruckTypes: [
TruckTypesEnum.dryVan,
],
accessorials: [
AccessorialsEnum.twicRequired,
AccessorialsEnum.ppe,
],
trailer: TrailerInput(
temperatureMax: 0,
temperatureMin: 0,
temperatureUnit: TemperatureUnitsEnum.f,
),
items: [
ItemInput(
description: "Items description",
weight: WeightInput(
weight: 100,
weightUnit: WeightUnitTypesEnum.lb,
),
units: UnitInput(
unitCount: 0,
unitType: ItemUnitTypesEnum.units,
),
handlingPiece: HandlingPieceInput(
pieceCount: 0,
pieceType: ItemPieceTypesEnum.pallets,
),
),
],
shortName: "Dem23",
loadDescription: "adhjahsdhajsdj",
routeDistanceMiles: 0.0,
routeDurationMinutes: 0,
stops: [
CreateStopInput(
appointmentType: AppointmentTypesEnum.alreadyMade,
startTime: "2021-05-03T00:00:00+02:00",
type: StopTypesEnum.pickup,
loadingType: LoadingTypesEnum.live,
locationInput: LocationInput(
locationName: "HOUSTON",
coordinates:
CoordinatesInput(lat: 29.608774, lng: -95.516164),
address: AddressInput(
full:
"14810 Fairway Pines Dr, Missouri City, TX 77489, USA",
city: "Missouri City",
state: "TX",
street: "Fairway Pines Drive",
streetNumber: 14810),
operationalContact: ContactInput(
contactName: "mr contact",
email: "hojayevkoch#gmail.com",
phoneNumber: "862615986",
notes: "notes lorem ipsum"),
schedulingContact: ContactInput(
contactName: "mr contact",
email: "hojayevkoch#gmail.com",
phoneNumber: "862615986",
notes: "notes lorem ipsum"),
)),
CreateStopInput(
appointmentType: AppointmentTypesEnum.toBeMade,
startTime: "2021-05-14T05:13:30+00:00",
endTime: "2021-04-27T17:35:00+00:00",
type: StopTypesEnum.dropoff,
loadingType: LoadingTypesEnum.live,
locationInput: LocationInput(
locationName: "COSTCO WHO,WEBSTER,TX,USA",
coordinates: CoordinatesInput(lat: 29.533604, lng: -95.136843),
address: AddressInput(
full: "1310 Jasmine St, Webster, TX 77598, USA",
city: "Webster",
state: "TX",
street: "Jasmine Street",
streetNumber: 1310,
),
operationalContact: ContactInput(
contactName: "mr contact",
email: "mrtest#gmail.com",
phoneNumber: "862615986",
notes: "notes lorem ipsum"),
schedulingContact: ContactInput(
contactName: "mr contact",
email: "mrtest#gmail.com",
phoneNumber: "862615986",
notes: "notes lorem ipsum"),
),
),
],
),
),
).toJson());
Following are the hardcodes on playground for createOffer:
mutation CreateShipment (
$input: OfferInput!
) {
createOffer(input: $input){
uuid
shipper_id
}
}
#variables
{
"input": {
"open_price": 30,
"shipment": {
"requested_truck_types": [
"DRY_VAN"
],
"accessorials": [
"TWIC_REQUIRED",
"SHIPPER_REQUIRES_MASK_GLOVES",
"PPE"
],
"items": [
{
"description": "Items description",
"handling_piece": {
"piece_type": "PALLETS",
"piece_count": 0
},
"units": {
"unit_type": "UNITS",
"unit_count": 0
},
"weight": {
"weight": 100,
"weight_unit": "LB"
}
}
],
"trailer": {
"temperature_max": 0,
"temperature_min": 0,
"temperature_unit": "F"
},
"short_name": "Dem",
"load_description": "load descriotajj adaksdjad",
"route_distance_miles": 0.0,
"route_duration_minutes": 0,
"stops": [
{
"appointment_type": "ALREADY_MADE",
"start_time": "2021-05-03T00:00:00+02:00",
"type": "PICKUP",
"loading_type": "LIVE",
"location_input": {
"location_name": "HOUSTON",
"coordinates": {
"lat": 29.608774,
"lng": -95.516164
},
"address": {
"full": "14810 Fairway Pines Dr, Missouri City, TX 77489, USA",
"city": "Missouri City",
"state": "TX",
"street": "Fairway Pines Drive",
"street_number" :14810
},
"operational_contact": {
"contact_name" : "mr contact",
"email" : "mrtest#gmail.com",
"phone_number" : "862615986",
"notes" : "notes lorem ipsum"
},
"scheduling_contact": {
"contact_name" : "mr contact",
"email" : "mrtest#gmail.com",
"phone_number" : "862615986",
"notes" : "notes lorem ipsum"
}
}
},
{
"appointment_type": "TO_BE_MADE",
"start_time": "2021-05-14T05:13:30+00:00",
"end_time": "2021-04-27T17:35:00+00:00",
"type": "DROPOFF",
"loading_type": "LIVE",
"location_input": {
"location_name": "COSTCO WHO,WEBSTER,TX,USA",
"coordinates": {
"lat": 29.533604,
"lng": -95.136843
},
"address": {
"full": "1310 Jasmine St, Webster, TX 77598, USA",
"city": "Webster",
"state": "TX",
"street": "Jasmine Street",
"street_number" :1310
},
"operational_contact": {
"contact_name" : "mr contact",
"email" : "hojayevkoch#gmail.com",
"phone_number" : "862615986",
"notes" : "notes lorem ipsum"
},
"scheduling_contact": {
"contact_name" : "mr contact",
"email" : "hojayevkoch#gmail.com",
"phone_number" : "862615986",
"notes" : "notes lorem ipsum"
}
}
}
]
}
}
}
and response
{
"data": {
"createOffer": {
"uuid": "933eee0a-8x82-46d6-xxx-018xxxxxxx40",
"shipper_id": "3"
}
},
"extensions": {
"lighthouse_subscriptions": {
"version": 1,
"channel": null,
"channels": []
}
}
}
to check if working graphql validation, I made mistake on datetime in starttime/endtime and get this:
{
"errors": [
{
"message": "Variable \"$input\" got invalid value {\"open_price\":30,\"shipment\":{\"requested_truck_types\":[\"DRY_VAN\"],\"accessorials\":[\"TWIC_REQUIRED\",\"SHIPPER_REQUIRES_MASK_GLOVES\",\"PPE\"],\"items\":[{\"description\":\"Items description\",\"handling_piece\":{\"piece_type\":\"PALLETS\",\"piece_count\":0},\"units\":{\"unit_type\":\"UNITS\",\"unit_count\":0},\"weight\":{\"weight\":100,\"weight_unit\":\"LB\"}}],\"trailer\":{\"temperature_max\":0,\"temperature_min\":0,\"temperature_unit\":\"F\"},\"short_name\":\"Dem\",\"load_description\":\"load descriotajj adaksdjad\",\"route_distance_miles\":0,\"route_duration_minutes\":0,\"stops\":[{\"appointment_type\":\"ALREADY_MADE\",\"start_time\":\"2021-05-03T00:00:00\",\"type\":\"PICKUP\",\"loading_type\":\"LIVE\",\"location_input\":{\"location_name\":\"HOUSTON\",\"coordinates\":{\"lat\":29.608774,\"lng\":-95.516164},\"address\":{\"place_id\":\"EjQxNDgxMCBGYWlyd2F5IFBpbmVzIERyLCBNaXNzb3VyaSBDaXR5LCBUWCA3NzQ4OSwgVVNB\",\"full\":\"14810 Fairway Pines Dr, Missouri City, TX 77489, USA\",\"city\":\"Missouri City\",\"state\":\"TX\",\"street\":\"Fairway Pines Drive\",\"street_number\":14810},\"operational_contact\":{\"contact_name\":\"mr contact\",\"email\":\"hojayevkoch#gmail.com\",\"phone_number\":\"862615986\",\"notes\":\"notes lorem ipsum\"},\"scheduling_contact\":{\"contact_name\":\"mr contact\",\"email\":\"hojayevkoch#gmail.com\",\"phone_number\":\"862615986\",\"notes\":\"notes lorem ipsum\"}}},{\"appointment_type\":\"TO_BE_MADE\",\"start_time\":\"2021-05-14T05:13:30+00:00\",\"end_time\":\"2021-04-27T17:35:00+00:00\",\"type\":\"DROPOFF\",\"loading_type\":\"LIVE\",\"location_input\":{\"location_name\":\"COSTCO WHO,WEBSTER,TX,USA\",\"coordinates\":{\"lat\":29.533604,\"lng\":-95.136843},\"address\":{\"full\":\"1310 Jasmine St, Webster, TX 77598, USA\",\"city\":\"Webster\",\"state\":\"TX\",\"street\":\"Jasmine Street\",\"street_number\":1310},\"operational_contact\":{\"contact_name\":\"mr contact\",\"email\":\"hojayevkoch#gmail.com\",\"phone_number\":\"862615986\",\"notes\":\"notes lorem ipsum\"},\"scheduling_contact\":{\"contact_name\":\"mr contact\",\"email\":\"hojayevkoch#gmail.com\",\"phone_number\":\"862615986\",\"notes\":\"notes lorem ipsum\"}}}]}}; Expected type DateTimeTz at value.shipment.stops[0].start_time; \"Data missing\"",
"extensions": {
"category": "graphql"
},
"locations": [
{
"line": 1,
"column": 25
}
]
}
],
"extensions": {
"lighthouse_subscriptions": {
"version": 1,
"channel": null,
"channels": []
}
}
}
which means all fields I was sending are correct, I think. Maybe requested field types are accepting valid input types from me but causing error while working/parsing them, I don't know, I am struggling with this for almost a week and as you can see two hardcodes (flutter/playground) are the same. My textfields and other inputs are ready but I can't run hardcode first of all :/ btw this is not expired token, for that I got unathorized action error.
Finally we could solve this issue. Issue was occuring on backend while parsing data come from my side. This was the flow of data:
user enters data
before mutation, flutter parsing data and graphql_flutter mutate
then, backend(in our case, php) does fields validation if all are ok, next, if not send validation errors to the client side.
after all, server starting storing data on db (here is the key point)
My issue was occuring on last stage, unnecessary model property was sent null, we get to know this by reading logs in laravel.log, so removing that field and migrate db, finally download and using "new" schema.graphql from playground resolved this issue. I hope this will be helpful later :)

flutter model for dynamic json array

so I have a json file(mock data). It goes something like this:
{
"data":
[
{
"id": "1",
"name": "Kacchi Biriyani",
"videoLink": "https://www.youtube.com/watch?v=K4TOrB7at0Y",
"author": "Alan Ford",
"category":"Biriyani",
"time": "15 min",
"steps": {
"step 1": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"step 2": "Suspendisse vel sapien elit"
},
"isFavorite": "yes"
},
{
"id": "2",
"name": "Mughal Biriyani",
"videoLink": "https://www.youtube.com/watch?v=aNVviTECNM0",
"author": "Ricky James",
"category":"Biriyani",
"time": "10 min",
"steps": {
"step 1": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
"step 2": "Suspendisse vel sapien elit",
"step 3": "Proin luctus, quam non dapibus pretium",
"step 4": "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
},
"isFavorite": "yes"
}
]
}
This is what I have as my model:
class RecipeModel {
final String id;
final String name;
final String videoLink;
final String author;
final String category;
final String time;
RecipeModel({
required this.id,
required this.name,
required this.videoLink,
required this.author,
required this.category,
required this.time,
});
factory RecipeModel.fromJson(Map<String, dynamic> json) {
return RecipeModel(
id: json['id'],
name: json['name'],
videoLink: json['videoLink'],
author: json['author'],
category: json['category'],
time: json['time'],
);
}
}
Now as you can see the steps:{...} are dynamic so it can be different for different items. One item can have 5 steps on the other hand another item can have more than 10 steps.
How can I write a dynamic List in my model for steps data that's coming from json?
Update 1:
List<RecipeModel> recipes = [];
Future<List<RecipeModel>> getRecipeData() async {
// var response = await http.get(
// Uri.https("jsonplaceholder.typicode.com", 'users'),
// );
String response = await DefaultAssetBundle.of(context)
.loadString('assets/json/recipe.json');
var result = json.decode(response);
for (var u in result["data"]) {
RecipeModel recipe = RecipeModel(
id: u['id'] ?? "",
name: u['name'] ?? "",
videoLink: u['videoLink'] ?? "",
author: u['author'] ?? "",
category: u['category'] ?? "",
time: u['time'] ?? "",
// steps: u["steps"],
);
recipes.add(recipe);
}
Cast the map of steps into a List<String> type using the from method.
// The steps from your api call.
var json = { "steps": { "step 1": "foo", "step 2": "bar" } }
// Convert the steps from the map to a List.
List<String> steps = List<String>.from(json["steps"].values);
// The result.
steps = ['foo', 'bar']
Update
This is what your RecipeModel should look like.
class RecipeModel {
final String id;
final String name;
final String videoLink;
final String author;
final String category;
final String time;
// The dynamic list of steps.
final List<String> steps;
RecipeModel({
required this.id,
required this.name,
required this.videoLink,
required this.author,
required this.category,
required this.time,
// The dynamic list of steps.
required this.steps,
});
factory RecipeModel.fromJson(Map<String, dynamic> json) {
return RecipeModel(
id: json['id'],
name: json['name'],
videoLink: json['videoLink'],
author: json['author'],
category: json['category'],
time: json['time'],
// The dynamic list of steps.
steps: List<String>.from(json['steps'].values),
);
}
Also just as a suggestion, make your variables match the data type it will be holding. For example, id can be and int instead of String, isFavorite can be a bool, etc. Trust me, it makes using them in dart code much easier.
Ex: if(isFavorite) {...} instead of if(isFavorite.toLowerCase() == "yes") {...}

What is wrong with seeder file and mongoose settings that I just can't save my seeder models?

Here is my Seeder file
var Product = require('../models/product.js');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/cart', { useMongoClient: true });
mongoose.Promise = global.Promise;
mongoose.connection.once('connected', function() {
console.log("Database connected successfully")
});
var products = [
new Product({
title: 'SuperMan Toy',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi totam praesentium commodi! Minima fugiat error possimus at ea quaerat a sit repudiandae laudantium. Ducimus quibusdam, assumenda iusto, doloribus quod debitis.',
price: 550,
imgPath: '#'
}),
new Product({
title: 'Batman Toy',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi totam praesentium commodi! Minima fugiat error possimus at ea quaerat a sit repudiandae laudantium. Ducimus quibusdam, assumenda iusto, doloribus quod debitis.',
price: 450,
imgPath: '#'
}),
new Product({
title: 'Hulk Toy',
description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quasi totam praesentium commodi! Minima fugiat error possimus at ea quaerat a sit repudiandae laudantium. Ducimus quibusdam, assumenda iusto, doloribus quod debitis.',
price: 650,
imgPath: '#'
}),
];
var done = 0;
for (i = 0; i < products.length; i++) {
products[i].save(function(err) {
if (err) {
console.log('Not Saved')
}
});
done++;
if (done === products.length) {
mongoose.disconnect();
}
}
you can check whole template at https://github.com/oaulakh/nodejs_testing
https://github.com/oaulakh/nodejs_testing/blob/master/seeder/productSeeder.js
I'm doing something wrong here, if yes how I can fix this so my mongo start saving my models?

Extjs Cannot read property 'dom' of null

In short, I have a login panel, which will be shown when onClick event is true, but I get error Cannot read property 'dom' of null. When I click second time - the panel is shown, but some elements of it are not shown. When I click for 3th time, the other elements has show, an last, I ger error "Cannot call method 'bringToFront' of undefined".
Ext.onReady(function() {
Ext.QuickTips.init();
Ext.ns('Site.login');
var globalKeyMap = new Ext.KeyMap(document);
globalKeyMap.accessKey = function(key, handler, scope) {
var h = function(n, e) {
e.preventDefault();
handler.call(scope || this, n, e);
};
this.on(key, h, scope);
};
var trackEnter = function(tf, e) {
if (e.keyCode == 13) {
e.stopPropagation();
doLogin();
}
}
var doLogin = function() {
var f = loginPanel.getForm();
if (f.isValid()) {
f.doAction(new Hypo.form.Action.DwrSubmit(f, {
waitMsg: 'Authentication is in progress',
invoker: function(form, cb) {
Login.login(form.getValues(), cb);
},
success: function(fp, o) {
loginForm.hide();
Ext.getBody().addClass("x-body-masked");
var w = loginForm;
w.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
w.mask.show();
if(o.result.data[0].authorities[0].authority=='ROLE_SUPERVISOR')
{
setTimeout('document.location = "AdminUsers.jsp"');
}
else if(o.result.data[0].authorities[0].authority=='ROLE_ADMIN')
{
setTimeout('document.location = "AdminUsers.jsp"');
}
else
{
setTimeout('document.location = "List.jsp"');
}
}
}));
}
}
var loginPanel = new Ext.FormPanel({
id: 'loginPanel',
labelWidth: 75, // label settings here cascade unless overridden
frame: false,
border: false,
bodyStyle:'padding:5px 5px 0',
width: 350,
defaults: {
width: 230
},
defaultType: 'textfield',
autoHeight: true,
items: [{
id: 'idxLogin',
fieldLabel: 'Login',
name: 'login',
allowBlank: false,
enableKeyEvents: true,
maxLength: 50,
listeners: {
'keypress': trackEnter
}
}, new Ext.form.TextField({
fieldLabel: 'Password',
name: 'password',
inputType: 'password',
enableKeyEvents: true,
maxLength: 50,
listeners: {
'keypress': trackEnter
}
})
]
});
var loginForm = new Ext.Window({
layout : 'fit',
width : 350,
closable : false,
modal: true,
plain : true,
title: 'User Authentication',
items: loginPanel,
autoHeight: true,
buttons: [{
text: 'OK',
handler: doLogin
},{
text: 'Cancel',
handler: function() {
loginForm.hide();
}
}],
listeners: {
'activate': function() {
setTimeout(function() {
Ext.getCmp("idxLogin").focus();
}, 100);
}
}
});
Site.login.window = loginForm;
});
Login
I tryed to add renderTo:'someDiv' and add to body a div with id "someDiv". But I received the same error message.
Please, help with that.