Seite 1 von 1
FieldList dynamisch füllen
Verfasst: Freitag 22. Januar 2016, 19:53
von meego
Hallo
Ich möchte eine wtforms FieldList mit nur einer Reihe im Template und dann dynamisch weitere gleiche Reihen hinzufügen (über jQuery). Wie mache ich das? Ich schaffe nur, via min_entries 7 Reihen anzuzeigen.
Im form:
Code: Alles auswählen
openinghours = FieldList(FormField(OpeningHour), min_entries=7, max_entries=15)
Im template:
Code: Alles auswählen
{% for entry in form.openinghours %}
<div class="row">
<div class="input-field col s3 m2">
{{ render_inputfield(entry.day)}}
</div>
<div class="input-field col s3 m2 l1">
{{ render_inputfield(entry.opening, class_="time") }}
</div>
<div class="input-field col s3 m2 l1">
{{ render_inputfield(entry.closing, class_="time") }}
</div>
<div class="input-field col s4 m3 l2">
{{ render_inputfield(entry.closed) }}
</div>
</div>
{% endfor %}
<div class="row">
<div class="input-field col s3 m2">
<a class="btn-floating waves-effect waves-light" id="add_button"><i class="material-icons">add</i></a>
</div>
</div>
Re: FieldList dynamisch füllen
Verfasst: Samstag 23. Januar 2016, 10:43
von Sirius3
@meego: wo hast Du Deinen JavaScript-Code der mit dem add-Button verbunden ist?
Re: FieldList dynamisch füllen
Verfasst: Samstag 23. Januar 2016, 15:55
von meego
Hallo Sirius. Hier:
Code: Alles auswählen
<script>
var $html_string = $('.row').text("bla bla bla");
$("add_button").on('click', function() {
$('#openinghours').('.row').append($html_string);
});
</script>
Obwohl das noch ziemlich provisorisch ist und wohl auch nicht funktioniert (jQuery ist Neuland für mich).
Re: FieldList dynamisch füllen
Verfasst: Sonntag 24. Januar 2016, 22:40
von Sirius3
@meego: das macht noch nicht viel Sinn. Wenn Du die Grundlagen von JavaScript drauf hast, solltest Du mal einen Blick in die jQuery-Dokumentation werfen.
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 13:03
von meego
Was mache ich falsch?
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 13:29
von Sirius3
@meego: $html_string ist kein html_string sondern eine jQuery-Elementesammlung, die Elemente enthält, die Du sicher nicht meinst. add_button ist eine ID und kein Tag. Ein String als Attribut für zu einem SyntaxError. Variablen die mit einem $ anfangen sind in JavaScript eher speziell. das hier ist kein PHP.
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 14:21
von meego
Ja, stimmt. Aber eine solche soll es auch sein. Ich glaube, jQuery Variablen werden aus Konventionsgründen mit einem $ begonnen, um sie von normalen JavaScript Variablen zu unterscheiden. Also müsste ich einfach das .html attribut verwenden?
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 15:54
von noisefloor
Hallo,
Ich glaube, jQuery Variablen werden aus Konventionsgründen mit einem $ begonnen, um sie von normalen JavaScript Variablen zu unterscheiden
Nein, das ist komplett falsch. jQuery ist auch nur JavaScript - sowas wie "jQuery" Variablen gibt's nicht. Also doch lieber nochmal in Ruhe die Doku lesen

Bzw. bei Wikipedia (
https://de.wikipedia.org/wiki/JQuery) ist es auch kurz erklärt.
Gruß, noisefloor
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 16:32
von BlackJack
So komplett falsch ist das nicht, ich habe das schon öfter gesehen das Namen für jQuery-Datentypen ein $ vorangestellt wird, weil man nicht selten gleiche oder sehr ähnliche Namen für die ”GUI”-Elemente und für die Daten hat. Beispielsweise ein `row`-Array und ein `$row` für das jQuery-Objekt das die Zeile in der HTML-Tabelle repräsentiert in das die Daten aus `row` als <td>s eingefügt werden sollen.
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 19:24
von meego
Eben Konvention:
Link
Interessieren täte mich aber eher, ob ich den For Loop für die FieldList brauche, wenn ich nur das erste Element anzeigen will.
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 19:57
von noisefloor
Hallo,
ok, komplett falsch ist falsch

Hatte das eben ein bisschen anders verstanden...
@meego: kannst du mal bitte alle relevanten Wtforms Klassen für das Beispiel posten - ich habe gerade noch ein Problem nachzuvollziehen, was die eigentlich vor hast. Nur ohne die `OpeningHour` Klasse ist das schwierig...
Gruß, noisefloor
Re: FieldList dynamisch füllen
Verfasst: Montag 25. Januar 2016, 22:02
von noisefloor
Hallo,
ich werkel gerade an einer privaten Rezepteverwaltung und - auch motiviert durch den Thread hier - bin ich das Thema "dynamische Formularerweiterung" auch mal angegangen.
Folgender Prototyp funktioniert:
Server:
Code: Alles auswählen
from bottle import route, run, template, debug, static_file, request
from my_forms2 import InputForm2
@route('/test')
def index():
form = InputForm2()
return template('dyn_form_in_wt2.html', form=form)
@route('/test', method='POST')
def post_data():
form_data = request.forms
form = InputForm2(form_data)
for k, v in form_data.items():
print(k, v)
if not form.validate():
print(form.errors)
else:
print('Form is valid')
return 'Done'
@route('/static/<filename>')
def server_static(filename):
return static_file(filename, root='/home/noisefloor/code/bottle/dyn_form/static')
debug=True
run(host='localhost', port=8080, reloader=True)
Formular:
Code: Alles auswählen
from wtforms.form import Form
from wtforms.fields import StringField, SelectField, DecimalField, FormField, FieldList
from wtforms.validators import NumberRange, InputRequired
UNITS = [('kg', 'kg'),
('g', 'g'),
('TL', 'TL'),
('EL', 'EL'),
('St', 'St')]
class InputForm(Form):
description = StringField('description',
[InputRequired()])
unit = SelectField('unit', choices=UNITS)
quantity = DecimalField('quantity',
[InputRequired(), NumberRange(min=0)],
places=3)
class InputForm2(Form):
ingredients = FieldList(FormField(InputForm), min_entries=1)
Template:
Code: Alles auswählen
<!DOCTYPE html>
<html>
<head>
<title>Dynamic Forms</title>
<script src="static/jquery-2.2.0.min.js"></script>
</head>
<body>
<form action="/test" method="POST">
<button class="add_field_button">Mehr Felder...</button>
<div class="input_fields_wrap">
<!-- here goes the form fields -->
</div>
<input type="submit">
</form>
<script>
$(document).ready(function() {
var max_fields = 10; //maximum input boxes allowed
var wrapper = $(".input_fields_wrap"); //Fields wrapper
var add_button = $(".add_field_button"); //Add button ID
var html_string = '{{ !form.ingredients }}<a href="#" class="remove_field">Remove</a>';
var x = -1; //initlal text box count
$(wrapper).append(make_string());
$(add_button).click(function(e){ //on add input button click
e.preventDefault();
if(x < max_fields){ //max input box allowed
x++; //text box increment
$(wrapper).append(make_string());
}
});
$(wrapper).on("click",".remove_field", function(e){ //user click on remove text
e.preventDefault(); $(this).parent('div').remove(); x--;
});
function make_string() {
var my_string = html_string;
var output = ''
output = my_string.replace(0, x+1, "g");
return output;
};
});
</script>
</body>
</html>
Das JS ist ein angepasstes Beispiel aus dem Web - das ist nicht alles auf meinem Mist gewachsen.
Vielleicht nützt es ja was für das ähnliche, hier beschriebene Problem
Gruß, noisefloor
Re: FieldList dynamisch füllen
Verfasst: Dienstag 26. Januar 2016, 22:53
von meego
Poste ich doch gerne für unseren Hobbykoch:
Code: Alles auswählen
class OpeningHour(Form):
day = SelectField(_('Wochentag'), [DataRequired()],
choices=[(0, _('Montag')), (1, _('Dienstag')), (2, _('Mittwoch')), (3, _('Donnerstag')), (4, _('Freitag')), (5, _('Samstag')), (6, _('Sonntag'))], coerce=int)
opening = StringField(_('von'))
closing = StringField(_('bis'))
closed = BooleanField(_('Geschlossen'))
class EnterBusiness(Form):
name = StringField(_('Business Name'), [DataRequired()])
street = StringField(_('Strasse'), [DataRequired()])
zipcode = StringField(_('Postleitzahl'), [DataRequired()])
city = StringField(_('Stadt'), [DataRequired()])
country = QuerySelectFieldWithChooseOption(_('Land'), query_factory=lambda: Country.query, get_label=lambda x: x.name)
description = TextAreaField(_('Beschreibung'))
phone = StringField(_('Telefon'), [DataRequired()])
website = StringField(_('Website'), [DataRequired()])
openinghours = FieldList(FormField(OpeningHour), min_entries=1, max_entries=21)
Neben den üblichen Daten soll man also dynamisch noch Öffnungszeiten zuschalten und eingeben können.
Re: FieldList dynamisch füllen
Verfasst: Mittwoch 27. Januar 2016, 08:03
von noisefloor
Hallo,
die Dynmaik kannst du ja von oben übernehmen, das Prinzip ändert sich ja nicht.
Ich würde das mit den Öffnungszeiten aber anders machen, nämlich je ein Select-Feld von 0-23 für die Stunden und eins für die Minuten von 0-59. 1) eliminierst du so "Freestyle"-Eingaben, die beim String-Feld möglich sind, 2) brauchst du den Eingabe-String nicht zerlegen, um daraus Zahlen für die DB zu machen.
Und ob man ein explizites "geschlossen" braucht, ist Ansichtssache. In dem Fall würde ich es eher implizit machen -> kein Zeiten für einen Tag in der DB -> geschlossen.
Gruß, noisefloor
Re: FieldList dynamisch füllen
Verfasst: Mittwoch 27. Januar 2016, 21:24
von meego
Hi
Das ist ganz schön viel Javascript, ich glaube mit jQuery müsste es einfacher gehen.
Ich verwende einen
jQueryTimepicker, kann man zwar überschreiben, aber in der Regel wird das keiner machen (vielleicht kann man das Überschreiben sogar irgendwie verhindern). Keine Ahnung, wie man das dann in ein db.Column(db.Time) kriegt. Aber jedes Problem zu seiner Zeit.

Re: FieldList dynamisch füllen
Verfasst: Mittwoch 27. Januar 2016, 22:45
von meego
Bei deinem Javascript meldet sich bei mir übrigens der Debugger:
jinja2.exceptions.TemplateSyntaxError: unexpected char '!' at 7296
Re: FieldList dynamisch füllen
Verfasst: Donnerstag 28. Januar 2016, 11:23
von noisefloor
Hallo,
Das ist ganz schön viel Javascript, ich glaube mit jQuery müsste es einfacher gehen.
Die Hauptarbeit macht doch jQuery. Lediglich das notwendige durchnummerieren der Namen der Formfelder ist plattes JS ohne Query.
jinja2.exceptions.TemplateSyntaxError: unexpected char '!' at 7296
Dann hast du mit Sicherheit den Übertrag von Bottle nach Flask falsch gemacht. in Bottle steht das `!` dafür, dass der nachfolgende String im Template _nicht_ escaped wird.
Was anders: du hast eine überschaubare endliche Zahl (nämlich 15) an Einträgen, von denen die 7 direkt angezeigt haben willst.
Warum generierst du nicht direkt die komplette Form, blendest die Elemente 8-15 aus und bei Bedarf nacheinander dynamisch ein (z.B. per jQuery). hat den Vorteil, dass die dich nicht um die korrekte manuelle Durchnummerierung des `name`Attributes des Form kümmern musst.
Gruß, noisefloor
Re: FieldList dynamisch füllen
Verfasst: Samstag 30. Januar 2016, 20:51
von noisefloor
Hallo,
Nachtrag bzw. Update: Das 1. Version des JavaScript funktioniert zwar grundsätzlich, hat aber diverse Stolperfallen wie nicht-fortlaufendes Hochzählen der Felder, wenn man ein Feld löscht oder das man auch alle Felder löschen kann.
Diese Version ist besser - weil sie die o.g. Macken nicht mehr hat:
Code: Alles auswählen
<!DOCTYPE html>
<html>
<head>
<title>Dynamic Forms</title>
<script src="static/jquery-2.2.0.min.js"></script>
</head>
<body>
<form action="/ingredients" method="POST">
<div class="input_fields_wrap">
<!-- here goes the form fields -->
</div>
<button class="add_field_button">Add field</button>
<button class="remove_field_button">Remove field</button>
<input type="submit">
</form>
<script>
$(document).ready(function() {
var max_fields = 20; //maximum input boxes allowed
var wrapper = $(".input_fields_wrap"); //Fields wrapper
var addButton = $(".add_field_button"); //Add button ID
var removeButton = $(".remove_field_button"); //Add button ID
var htmlString = '<div id="input_fields_0">{{ !form.ingredients }}</div>';
var field_counter = 0;
$(wrapper).append(makeString()); //add the first form
$(addButton).click(function(e){ //on add input button click
e.preventDefault();
if(field_counter < max_fields){ //max input box allowed
field_counter++;
$(wrapper).append(makeString());}
else { window.alert('max number of ingredients reached!')}
});
$(removeButton).click(function(e){ //on remove input button click
e.preventDefault();
if(field_counter > 0){ //make sure at least one field is there
$('#input_fields_'+field_counter).remove();
field_counter--;}
else { window.alert('Cannot delete, one input has to remain.')}
});
function makeString() {
var myString = htmlString;
return myString.replace(/0/g, field_counter);
};
});
</script>
</body>
</html>
Gruß, noisefloor