1

I have a html file with some elements and a python file that handles requests with flask like below:

@app.route('/changeColor', methods=['POST'])
def change_color():
    colors = ['red', 'black', 'purple', 'yellow', 'white', 'pink', 'grey', 'green']
    i = random.randint(0, 2)
    rand_col = colors[i]
    return rand_col

anyone sends a request to this URL, it will return a random color, but what I want is when someone sends a request to this URL, it would change the background color of an element in my HTML page dynamically(i mean I don't want my page to reload or sth).any suggestions would help me.

Ahmad
  • 1,618
  • 5
  • 24
  • 46
  • Hello, I have an question about your system. Are you want to change color on any opened (by you or another one user) page? – Jefferson Houp Nov 29 '19 at 15:19
  • @JeffersonHoup hello, actually right now there's just one user, but in the future...yes..i would like to change the element's color in any opened pages.(and one other thing..there's just one single page including my elements) – Faranak Hdi Nov 29 '19 at 15:24
  • About my answer: it will update page color at any opened page at each request to API endpoint. So if you will send one request - color will be changed in all opened pages for all users ) – Jefferson Houp Nov 29 '19 at 16:24

2 Answers2

0

So, well. Hello, firstly.

There's a little bit more than just python problem. It's system architecture question now.

Better way here is use socket connection for this task. We will add javascript object WebSocket to html page which will create connection to backend and will wait for messages from it:

const socket = new WebSocket('ws://localhost:8080');

For sure, we will add socket listener to backend part. It can be any library working with WebSockets: this one or maybe this one. Usually, I use the second.

After creating socket listener at backend and frontend parts of our system - this will work this way:

  1. User opened html-page with javascript.

  2. Javascript opened socket-connection with backend.

  3. Backend accepted connection.

Now all opened pages will wait for some messages from backend. And we should upgrade listener at backend :) This listener (working 24/7 by infinity loop - best way to do that right - look at asyncio) will check database/file/process/something (this is another question) to know about new successful request to your API and will send message to all opened sockets. At frontend part - javascript will got message from socket-connection and will render new color to DOM-element.

There's a lot of things in this system which should be well thought out, but I think this is a way to do what you want. And for sure, this is a way to know how do that and more.

Jefferson Houp
  • 858
  • 1
  • 7
  • 17
  • Wow ! Thank you ! it seems it would work !...im implementing it, just one question, u consider back-end as server and front-end as client, right? – Faranak Hdi Nov 29 '19 at 16:41
  • @FaranakHdi yes, you are right ) frontend - part of code which working on the client-side (in browser), to be clear :) – Jefferson Houp Nov 29 '19 at 16:42
0

I'm going to answer this question exactly, although be aware that setting page colour can be done entirely on the frontend, and probably shouldn't require a request to the server to get the actual colour.

This answer perfectly explains now to do this in Javascript alone, and avoid that request to the server every time someone changes the color.


If you did want to make this request to the server (for learning purposes, say) you could do. Let's modify your flask route slightly to account for a few things:

@app.route('/changeColor', methods=['GET'])
def change_color():
    colors = ['red', 'black', 'purple', 'yellow', 'white', 'pink', 'grey', 'green']
    i = random.randint(0, len(colors)-1)
    rand_col = colors[i]
    return {'color': rand_col}, 200

We have:

  • Changed the request method to GET.
  • Changed the randomization line, to account for the length of the colors list. Adding more items to the list will automatically include them all in the random selection now.
  • Returned a dictionary with the key 'color' and value of rand_col. This dictionary will automatically be turned into JSON by flask. Also we have added the 200 response code.
@app.route('/')
def index():
    return render_template('index.html')
  • Here we've added a separate route to render the frontend template, users hit this page, and the change_color route specifically deals with returning a colour.

Now for the template. I'm actually using jquery for this which is included from cloudflare's CDN along with an SNI tag for security reasons.

We create a button in the HTML, with the class changecolor then use a Jquery selector to call the AJAX functon when the button is clicked.

This is the contents of templates/index.html:

<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
</head>
<body>
  <p>I am the page text.</p>
  <button class="changecolor" type="button">Change my Colour</button>
<script type='text/javascript'>
$(function() {
  // This catches the button click
  $('.changecolor').click(function() {

    // This does the ajax call to the server (GET Request)
      $.ajax({
        type: 'GET',
        // Dynamically set the URL for the python `change_color`
        // function.
        url: '{{ url_for("change_color") }}',
        success: function(data) {
          // Actually set the page color, if the request is suecessful
          document.body.style.backgroundColor = data['color']; 
      }
    });
  });
});
</script>
</body>
</html>
  • Notice that instead of providing the URL as /changeColor we use Jinja2's template functionality, this time the url_for function to dynamically set the corresponding URL for the change_color function in the Python code. (more info)

Now on your front-end you should be able to click the button and change the page color:

color selector

v25
  • 7,096
  • 2
  • 20
  • 36