A textarea mit einem Zeichenzähler widget für Flask, WTForms und Bootstrap
Das Hinzufügen eines WTForms textarea widget sieht einfach aus, aber die Unterschiede zwischen Linux und Windows verursachen unerwartete Probleme.
Ich hatte gehofft, Ihnen heute sagen zu können, dass Sie jetzt die Blog-Posts dieser Website kommentieren können. Das hätte bedeutet, dass ich die erste Implementierung des Kommentarsystems abgeschlossen hätte. Leider bin ich über einige Probleme gestolpert, ja natürlich, ich bin Programmierer, und eines davon betraf den TextAreaField.
Ich wollte nur eine einfache erweiterte Version des WTFormulars TextAreaField, fügen Sie einfach ein Zeichenzählerfeld unter dem textarea hinzu, und das war's. Ich dachte, das würde ein paar Stunden dauern, aber ich habe mich total geirrt, aber ich habe das irgendwie gelöst und dachte, ich könnte Ihnen das mitteilen. Lassen Sie mich Ihre Gedanken wissen ... hmmm ... wenn die Kommentare online sind ... :-)
Ich verwende Bootstrap und jQuery. Für jQuery wurde die textarea mit den restlichen Zeichen mehrfach dokumentiert. Viele Lösungen schlagen vor, dem Beispiel von Twitter zu folgen. Das bedeutet, dass Sie den vollständigen Text auch dann anzeigen, wenn die Anzahl der Zeichen die zulässige Anzahl übersteigt. Wenn die Anzahl der Zeichen die zulässige Anzahl überschreitet, zeigen wir die Anzahl der Zeichen in der Farbe Rot an. Kein Problem, ich werde es umsetzen.
Angabe der maximalen Anzahl von Zeichen an einer Stelle
Ich möchte, dass der widget universell ist, also keine fest programmierten Werte enthält. jQuery wird verwendet, um die tatsächliche Anzahl von Zeichen zu zählen, aber woher weiß jQuery , was die maximal zulässige Anzahl ist? Wir können Konstanten definieren und diese überall verwenden, aber es ist flexibler, zusätzliche HTML5-Datenattribute für die textarea zu implementieren:
- data-char-count-min
- Daten-Chart-Zahl-Max
Wir fügen ein zusätzliches Element hinzu, das die verbleibende Anzahl von Zeichen unterhalb des textarea-Codes anzeigt. Die Datenattribute können durch den jQuery -Code referenziert und zur Berechnung der Anzahl der verbleibenden Zeichen verwendet werden.
Umsetzung
Auch hier sehen wir uns zunächst den Code WTForms für den TextAreaField an. Siehe auch einen früheren Beitrag. Ich habe diesen Code kopiert und in diesen modifiziert:
class TextAreaWithCounterWidget(object):
"""
Renders a multi-line text area.
`rows` and `cols` ought to be passed as keyword args when rendering.
"""
def __init__(self):
pass
def __call__(self, field, **kwargs):
fname = 'TextAreaWithCounterWidget - __call__'
kwargs.setdefault('id', field.id)
if 'required' not in kwargs and 'required' in getattr(field, 'flags', []):
kwargs['required'] = True
return HTMLString('<textarea %s>%s</textarea>' % (
html_params(name=field.name, **kwargs),
escape(text_type(field._value()), quote=False)
) + '<span class="" id="' + field.id + '-char-count-num' + '"></span>' )
class TextAreaWithCounterField(StringField):
"""
This field represents an HTML ``<textarea>`` and can be used to take
multi-line input.
"""
widget = TextAreaWithCounterWidget()
Dann benutze ich sie wie folgt:
def strip_whitespace(s):
if isinstance(s, str):
s = s.strip()
return s
class ContentItemCommentForm(FlaskForm):
message = TextAreaWithCounterField(_l('Your message'),
render_kw={'data-char-count-min': 0, 'data-char-count-max': 1000, 'rows': 4},
validators=[ InputRequired(), Length(min=6, max=1000) ],
filters=[ strip_whitespace ] )
submit = SubmitField(_l('Add'))
Manchmal sind die Dinge einfacher als erwartet. Wir können unsere neuen Parameter einfach mit render_kw in das Formular einfügen. Dann werden sie in der widget als Attribute an die textarea übergeben. Wenn wir wollen, können wir auf diese Parameter auch in der widget mit kwargs zugreifen. Wir können sie als:
data_char_count_max = kwargs['data-char-count-max']
Wir können sie auch aus kwargs herausnehmen, also lesen und entfernen. Dann erscheinen sie nicht als Attribute im textarea:
char_count_max = kwargs.pop('char_count_max', None)
Aber es gibt keinen Grund, dies hier zu verwenden. Innerhalb des widget können wir auch auf die Werte des Längen-Validators zugreifen, aber auch hier ist dies nicht notwendig.
Ich habe auch die Anzahl der Zeilen in render_kw angegeben. Diese wird an das Feld textarea übergeben. Das generierte HTML wird mit dem zusätzlichen Element angehängt, das die verbleibende Anzahl von Zeichen anzeigt. Die ID dieses Elements wird aus der ID textarea konstruiert:
field.id + '-char-count-num'
Der Filter strip_whitespace wird aufgerufen, um den vorderen und hinteren Weißraum zu beschneiden.
Der Code jQuery ist nicht so schwierig. Ich verwende Bootstrap, die Klassen ändern die Farbe und setzen die Füllung:
function update_character_count(textarea_id){
var char_count_num_id = textarea_id + '-char-count-num';
if( ($("#" + textarea_id).length == 0) || ($("#" + char_count_num_id).length == 0) ){
// must exist
return;
}
var char_count_min = parseInt( $('#' + textarea_id).data('char-count-min'), 10 );
var char_count_max = parseInt( $('#' + textarea_id).data('char-count-max'), 10 );
var remaining = char_count_max - $('#' + textarea_id).val().length;
$('#' + char_count_num_id).html( '' + remaining );
if(remaining >= 0){
$('#' + char_count_num_id).removeClass('text-danger');
$('#' + char_count_num_id).addClass('pl-2 text-secondary');
}else{
$('#' + char_count_num_id).removeClass('text-secondary');
$('#' + char_count_num_id).addClass('pl-2 text-danger');
}
}
und:
$(document).ready(function(){
...
// comment form: character count
update_character_count('comment_form-message');
$('#comment_form-message').on('change input paste', function(event){
update_character_count('comment_form-message');
});
}
Prüfung und Nichtübereinstimmung bei der Zeichenanzahl
Jetzt können wir mit dem Testen des neuen TextAreaWithCounterField beginnen. Alles sah gut aus, bis ich anfing, neue Linien zu betreten. Die Länge wurde von jQuery korrekt angegeben, was bedeutet, dass sie als ein einziges Zeichen gezählt wurden. Aber der WTForms -Validator sagte, dass die maximale Länge überschritten wurde. Noch einmal zur Fehlerbehebung: In der widget habe ich die von WTForms empfangenen Zeichen gedruckt:
message = field.data
if message is None:
current_app.logger.debug(fname + ': message is None')
else:
current_app.logger.debug(fname + ': message = {}, len(message) = {}, list(message) = {}'.format(message, len(message), list(message)))
Dies brachte mir folgendes Ergebnis:
len(message) = 4, list(message) = ['a', '\r', '\n', 'b']
jQuery zählt \r\n als ein einzelnes Zeichen, aber WTForms zählt es als zwei Zeichen. Wenn wir uns in den Code WTForms , validators.py, einarbeiten, sehen wir, dass er die Len-Funktion Python zur Bestimmung der Länge verwendet:
l = field.data and len(field.data) or 0
Verständlich, aber in diesem Fall ist es falsch! Was ist zu tun? Ich wollte die Standardvalidierungsfunktion WTForms nicht außer Kraft setzen. Glücklicherweise haben wir das Filterfeld, das vor der (!) Validierung aufgerufen wird. Ich habe bereits strip_whitespace verwendet und einen neuen Filter hinzugefügt:
def compress_newline(s):
if isinstance(s, str):
s = s.replace("\r\n", "\n")
s = re.sub(r'\n+', '\n', s)
return s
Dieser Filter ersetzt \r\n durch einen einzelnen \n. Außerdem ersetzt es mehrere \n -Zeichen durch ein einziges \n. Letzteres ist nur ein sehr primitiver Schutz gegen unvermeidlich falsche (und verrückte) Unterwerfungen. Die Filterlinie wird dann:
filters=[ strip_whitespace, compress_newline ] )
Jetzt funktionierte es wie beabsichtigt.
Zusammenfassung
Die Verwendung von render_kw ist eine einfache Möglichkeit, Parameter an den widget zu übergeben. Ich habe im Internet nach dem Problem \r\n gesucht, konnte aber keine Hinweise finden. Bitte sagen Sie mir nicht, dass ich der Einzige bin. Das Problem wird durch eine Diskrepanz zwischen den Systemen Windows und Linux verursacht. Außerdem benötigt die Kodierung von Javascript/jQuery Zeit, wenn Sie dies nicht ständig tun.
Links / Impressum
How to specify rows and columns of a <textarea > tag using wtforms
https://stackoverflow.com/questions/4930747/how-to-specify-rows-and-columns-of-a-textarea-tag-using-wtforms
New line in text area
https://stackoverflow.com/questions/8627902/new-line-in-text-area
Using data attributes
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
WTForms - Fields
https://wtforms.readthedocs.io/en/stable/fields.html
WTForms - Widgets
https://wtforms.readthedocs.io/en/stable/widgets.html
Einen Kommentar hinterlassen
Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.
Kommentare (1)
Eine Antwort hinterlassen
Antworten Sie anonym oder melden Sie sich an, um zu antworten.
Thanks for sharing! I wrote long comment but token has expired since I was reading the other tabs and I lost my comment :/. In short - great article and real demo, which I can see here, while typing this one again.
Neueste
- Don't Repeat Yourself (DRY) mit Jinja2
- SQLAlchemy, PostgreSQL, maximale Anzahl von Zeilen pro user
- Anzeige der Werte in den dynamischen Filtern SQLAlchemy
- Sichere Datenübertragung mit Public Key Verschlüsselung und pyNaCl
- rqlite: eine hochverfügbare und distverteilte SQLite -Alternative
- Sollte ich meinen Docker Swarm auf Kubernetes migrieren?
Meistgesehen
- Verwendung von Pythons pyOpenSSL zur Überprüfung von SSL-Zertifikaten, die von einem Host heruntergeladen wurden
- Verwendung von UUIDs anstelle von Integer Autoincrement Primary Keys mit SQLAlchemy und MariaDb
- Verbindung zu einem Dienst auf einem Docker -Host von einem Docker -Container aus
- SQLAlchemy: Verwendung von Cascade Deletes zum Löschen verwandter Objekte
- PyInstaller und Cython verwenden, um eine ausführbare Python-Datei zu erstellen
- Flask RESTful API Validierung von Anfrageparametern mit Marshmallow-Schemas