4

I've made a tag list that takes user input and binds it to another input field as a list of tags. However, after weeks messing around with Javascript and JQuery the only way (and importantly an elegant way) I've been able to do it is using Brython. Unfortunately, that seems to be disabling the jinja2 template in some way so nothing is submitted to the database. So, after all that, my question is, can such a seemingly simple task be done natively in Flask?

Here is the essence of how the Brython script works https://jsfiddle.net/5nt39deo/2/ but the code that the question is about is below:

<form action="" id="homeForm" class="centered" role="form" method="post">
    {{ form1.hidden_tag() }}
    {{ form1.toppings(type="text",id="homeInput",autocomplete="off",list="topps",placeholder="Toppings...") }}
    <datalist id="topps">{% for top in topps %}<option value="{{ sym }}">{% endfor %}</datalist>
    <button action="" type="submit" id="homeAddTags" class="button">Add</button><br><br>
    {{ form1.tags(id="tagList") }}<br>
    {{ form1.agree(id="homeAgreement") }}
    {{ form1.agree.label() }}<br><br>
    <button type="reset" id="homeResetTags" class="button">Reset</button>
    {{ form1.sendtags(type="submit",class_="button",id="homeSubmit") }}<br><br>
</form>


<script type="text/python" id="script1">
    from browser import document, html, window, console, alert

    storage = []

    def addTag(e):
        item = document['homeInput'].value
        if item not in storage and item != '':
            storage.append(item)
            document['homeInput'].value = ''
            document['tagList'].textContent = storage
        else:
            alert('Tag already added.')
            document['homeInput'].value = ''

    def resetTags(e):
        storage = []
        document['homeInput'].value = ''
        document['tagList'].textContent = storage

    document['homeAddTags'].bind('click', addTag)
    document['homeResetTags'].bind('click', resetTags)
</script>
Jack
  • 313
  • 5
  • 22
  • Could you please provide us your not working Flask attempt to do it? – Daniele Ricci Jun 16 '20 at 14:21
  • @DanieleRicci I couldn't make a fiddle of the jinja2 templates but I've added the form code above. – Jack Jun 16 '20 at 14:24
  • You say you are looking for a native flask solution, do you mean that brython is sufficient as well? Or do you want the page to be rendered again after each ‘oninput’-event? – Chiel Jun 19 '20 at 09:07
  • @Chiel Brython works but it seems to be disabling the "tagList" input in a way I don't quite understand so I'm trying to get rid of it to simplify my code and hopefully solve the tagList problem. – Jack Jun 19 '20 at 14:20
  • @JackPutter so would this question be answered if someone made the python version of Kalovelo's answer? If not, could you clarify the problem a bit more? – Chiel Jun 19 '20 at 15:09
  • @Chiel Yes but specifically within the Flask framework so that I don't have to load the Brython script. So, that means transferring the function to the backend models.py or routes.py and calling it from the front end but I'm not sure how to do that. – Jack Jun 19 '20 at 15:46

2 Answers2

3

Check out this native javascript solution

...
 <input type="text" id="text" placeholder="Enter something" oninput="outputUpdate();">
...
<script type="text/javascript" id="script2">

function outputUpdate(e){
let currentText=document.getElementById('text').value;

document.getElementById('output').innerHTML = currentText;

</script>

https://jsfiddle.net/kalovelo/z5ngxp31/

Kalovelo
  • 51
  • 1
  • 4
  • This is great, thank you. I wonder if there is a way to do it in Flask that avoids JavaScript though? – Jack Jun 14 '20 at 07:22
  • 1
    Hi, you could, in order to use less code add `this.value` as a parameter of `outputUpdate()` like so: `oninput="outputUpdate(this.value);"`. Then you could pass set `document.getElementById('output').innerHTML` directly to `e`, the value of the input directly. Thus skip this line: `let currentText = ...`! – Chiel Jun 16 '20 at 15:27
2

You can try something like that which I have explained below.

<input type="text">
<div id="output"></div>

Here is the Javascript: Instead of calling a javascript function explicitly, You can simply attach a keyup event to your input box. You can check this out here Fiddle

<script type="text/javascript">
var $onKeyUpEvent = document.getElementsByTagName('input')[0];
$onKeyUpEvent.addEventListener('keyup', (v) => {
    document.getElementById('output').innerHTML = v.target.value;
})
</script>
Kamal Kant
  • 1,031
  • 1
  • 12
  • 22