OndrejKunc / flutter_dynamic_forms

A collection of flutter and dart libraries allowing you to consume complex external forms at runtime.
MIT License
204 stars 60 forks source link

Can we create our own xml or json structure? #47

Closed kalismeras61 closed 5 years ago

kalismeras61 commented 5 years ago

Hello, I have one project based on create dynamic form from xml/json. I saw your repo and it look awesome. But i don't have more detail in json object and my json structure is very simple like below. just need 3 type of element. Input's for strings,float and intergers, Date for dates and DropDown for List's.( Searcable dropdown)

So can create my own structure ? or i must change my server response to your structure?

{ "data": [ { "type": "Checkbox", "label": "Cari Hesaplar", "value": 1, "list_fields": [ { "label": "Label 1", "value": 1 }, { "label": "Label 2", "value": 2 }, { "label": "Label 3", "value": 3 } ] }, { "type": "Input", "label": "Sözleşme No" }, { "type": "Date", "label": "Sözleşme Tarihi" }, { "type": "Date", "label": "Sözleşme Bitiş Tarihi" } ] }

OndrejKunc commented 5 years ago

Hi, thanks for opening the issue. I am aware that documentation about exact JSON and XML format is not very good right now.

I think easiest way for you is to change your server response to look something like the json in the example project. You would need to wrap your components inside some root component (for example container) instead of the data property. Also, you need to change "type" for "@name" and start lower case letters in component names. I am also a little bit confused about the "list_fields" property inside the checkbox. Shouldn't it be outside the checkbox?

If for some reason you can't easily change your server response, it is still quite easy to write your own parsing logic. You would just need to implement those two classes and pass it to the FormManagerBuilder. If you are interested in the decision behind JSON parser you can check this thread.

In your case, I would also probably recommend not to use flutter_dynamic_forms_components and write your components from scratch, so you can have greater control over all the properties. You would just need to reference flutter_dynamic_forms. See the other example project which implements its own small set of components.

kalismeras61 commented 5 years ago

@OndrejKunc thank you for your detailed answer. I think i need to create my own components as i see i just need only 3 class for each component.? When i created my own components only i can use this package parserNode methods? isnt it?

One more question if i need some other TextField properties like borders can i handle this renderer part? or i need add parserNoder for InputBorder ? I'm a little bit confused.

OndrejKunc commented 5 years ago

Yes, you need to provide 3 classes - Model, Parser and Renderer.

ParserNode is just a little abstraction over one 'node' in the underlying format. Now there are two concrete implementations - JsonParserNode and XmlParserNode. JsonParserNode represents one Json object. In your case this would be { "type": "Date", "label": "Sözleşme Bitiş Tarihi" } and XmlParserNode represents single XML element. When you are passing JsonFormParserService to the FormManagerBuilder the JsonParserNode will be used. The reason why this abstraction exists is that you can have only one Parser class for your component which would work on both JSON and XML.

One more question if i need some other TextField properties like borders can i handle this renderer part? or i need add parserNoder for InputBorder ? I'm a little bit confused.

Yes, the idea is that in your renderer you can return any Flutter widget you like. If you need to set your border, you can just do it in the renderer class. However if you want to set the border on the server and let the server decide about the border by providing border value in the JSON response, then you would need to add it to the model and parser class as well and use this value in the renderer class to render the correct border.

kalismeras61 commented 5 years ago

thanks for informations. I'm going to try it the way you explain to above . will bother you if I hang out :))

kalismeras61 commented 5 years ago

Updated: Found The Problem.

Hi @OndrejKunc , i created my own components and for dropdown i just used your parser and model except renderer part. I created my own searchable dropdown widget but i saw one problem.

The problem is when i select any item on list on android it will updated the default value but on iphone emulator does not indicate change to default value. ( i printed selected value it looks true)

Did you test your plugin both of android and ios side?

kalismeras61 commented 5 years ago

Hi @OndrejKunc i have been good at many things with this package but i'am stuck on one problem. I get my form details from server, there is no problem at all i created my own inputs, dropdown and date components.

Lets say i have search form (look at below xml as you see)and have one date element but i have to sent server one id but 2 value. Because it is search form if the user selects only the start date, they will see the today current values.if they selects an end date, they will see the values before the end date. if users selects the start and end date, they will be able to search between the two dates.

The problem is i just get only one date element from server but i have to send one id but two value to server. Do you have an idea about that ?

Note : Btw i will send pull request for date component.

<?xml version="1.0" encoding="UTF-8"?>
<form id="form1">
  <input id="Sözleşme No" textInputType="text">
  </input>
  <input id="Evrak No" textInputType="number">
  </input>
  <dropdownButton id="Cari Hesaplar" value="Kets Bilgisayar">
    <dropdownOption value="Kets Bilgisayar" label="Kets Bilgisayar"/>
    <dropdownOption value="Vitek Otomasyon" label="Vitek Otomasyon"/>
    <dropdownOption value="RCT Solutions" label="RCT Solutions"/>
  </dropdownButton>
  <date id ="Sözleşme Tarihi" label="Sözleşme Tarihi" value=""></date>
</form>
OndrejKunc commented 5 years ago

Hi, I'm glad to hear about your progress!

So I suppose you are using the List<FormItemValue> data = formManager.getFormData() to collect your data from the form right? This method will go through the whole form and collects all the properties, which are marked as an isImmutable: false in the parser. You can have multiple properties marked isImmutable: false on one component so there will be one FormItemValue for each of your property.

I would simply add two properties on your date component model, something like startDate and endDate and set their default values in the parser object and set them as isImmutable: false. It is not a problem if you don't have those properties filled in your XML, because they will be initialized to the default values via the parser. And once you have them on the model, you can fill them via ChangeValueEvent in your renderer. Then you can collect those values using formManager.getFormData() so you will have 2 FormItemValues, one for startDate and one for endDate both with the same Id. I don't know how you send those data back to your server, but you can take those objects and group them by Id and send them together.

Hope this helps.

kalismeras61 commented 5 years ago

@OndrejKunc i tired someting but i get this error

Exception: Can't get expressions for value Could you help me for right implementation ? Here is my model class; https://dpaste.de/mWs5 Here is the my parser https://dpaste.de/1epZ And here is the my renderer part ( it is a little bit complicated); https://dpaste.de/tquk

Default xml is below;


<?xml version="1.0" encoding="UTF-8"?>
<form id="form1">
  <input id="Sözleşme No" textInputType="text">
  </input>
  <input id="Evrak No" textInputType="number">
  </input>
  <dropdownButton id="Cari Hesaplar" value="Kets Bilgisayar">
    <dropdownOption value="Kets Bilgisayar" label="Kets Bilgisayar"/>
    <dropdownOption value="Vitek Otomasyon" label="Vitek Otomasyon"/>
    <dropdownOption value="RCT Solutions" label="RCT Solutions"/>
  </dropdownButton>
  <date id ="Sözleşme Tarihi" label="Sözleşme Tarihi" startDate="" endDate=""></date>
</form>
kalismeras61 commented 5 years ago

It was my fault :) I found the problem. The peoblem is i forgot the change default propertyName . ChangeValueEvent send default propertyName "value" so why i get this error.

 dispatcher(
                                  ChangeValueEvent(
                                    value: picked1.toString(),
                                    elementId: element.id,
                                    propertyName:
                                        model.Date.endValuePropertyName, // change it with this.
                                  ),
                                );
OndrejKunc commented 5 years ago

Awesome :) Yeah, that default property name "value" is something we consider to remove anyway. It seemed like a good idea at the beginning but it can be quite confusing.