Sending Form Data via pure JavaScript:

  • still in home.html
  • print form data in a loop:

    1. <script>
    2. function handleTweetCreateFormDidSubmit(event) {
    3. event.preventDefault()
    4. const myForm = event.target
    5. const myFormData = new FormData(myForm)
    6. for(var myItem of myFormData.entries()){
    7. console.log(myItem)
    8. }
    9. //console.log(event)
    10. }
    11. //...
    12. </script>

    to test, runserver and send something
    image.png
    in the console, we see “csrfmiddlewaretoken”, “next”, and “content”
    also, the input text is still not updated into tweets.

  • and also in home.html, test 2 other checkpoints

    1. <script>
    2. function handleTweetCreateFormDidSubmit(event) {
    3. event.preventDefault()
    4. const myForm = event.target
    5. const myFormData = new FormData(myForm)
    6. const url = myForm.getAttribute("action")
    7. const method = myForm.getAttribute("method")
    8. console.log(url, method)
    9. }
    10. //...
    11. </script>

    to test, runserver and send something
    image.png
    so
    url = “/create-tweet”
    method = “POST”

  • Then, send form data as load_tweets() in home.html

    1. <script>
    2. function handleTweetCreateFormDidSubmit(event) {
    3. event.preventDefault()
    4. const myForm = event.target
    5. const myFormData = new FormData(myForm)
    6. const url = myForm.getAttribute("action")
    7. const method = myForm.getAttribute("method")
    8. const xhr = new XMLHttpRequest()
    9. xhr.open(method, url)
    10. xhr.onload = function() {
    11. const serverResponse = xhr.response
    12. console.log(serverResponse)
    13. }
    14. xhr.send(myFormData)
    15. }
    16. //...
    17. </script>

    to test, runserver and send something:
    image.png
    This time we print the form data, and we see a complete HTML form format.
    The form data is sent as a XMLHttpRequest()
    Also, after we refresh the page:
    image.png
    …this time the content is created successfully.

  • To make tweets page is reloaded in time, we apply loadTweets()

    1. <script>
    2. function handleTweetCreateFormDidSubmit(event) {
    3. event.preventDefault()
    4. const myForm = event.target
    5. const myFormData = new FormData(myForm)
    6. const url = myForm.getAttribute("action")
    7. const method = myForm.getAttribute("method")
    8. const xhr = new XMLHttpRequest()
    9. xhr.open(method, url)
    10. xhr.onload = function() {
    11. const serverResponse = xhr.response
    12. console.log(serverResponse)
    13. const tweetsEl = document.getElementById("tweets")
    14. loadTweets(tweetsEl)
    15. }
    16. xhr.send(myFormData)
    17. }
    18. //...
    19. </script>

Handling Ajax Requests

  • Ajax stands for “Asynchronous JavaScript and XML”, it’s the current situation that we are handling
  • https://en.wikipedia.org/wiki/Ajax_(programming))

  • we add a checking step in /tweets/views.py to make sure is that request ajax

    1. def tweet_create_view(request, *args, **kwargs):
    2. print("ajax", request.is_ajax()) # here
    3. form = TweetForm(request.POST or None)
    4. print('post data is', request.POST)
    5. next_url = request.POST.get("next") or None
    6. # print('next_url', next_url)
    7. if form.is_valid():
    8. obj = form.save(commit=False)
    9. obj.save()
    10. if next_url != None and is_safe_url(next_url, ALLOWED_HOSTS):
    11. return redirect(next_url)
    12. form = TweetForm()
    13. return render(request, 'components/form.html', context={"form" : form})

    to test, as usual runserver and send something:
    image.png
    and watch the console:

    1. ajax False

    so it isn’t an ajax request.

  • HttpRequest.is_ajax() is actually looking for an ajax header

  • we can manually set the header in home.html

    1. function handleTweetCreateFormDidSubmit(event) {
    2. event.preventDefault()
    3. const myForm = event.target
    4. const myFormData = new FormData(myForm)
    5. const url = myForm.getAttribute("action")
    6. const method = myForm.getAttribute("method")
    7. const xhr = new XMLHttpRequest()
    8. const responseType = "json"
    9. xhr.responseType = responseType
    10. xhr.open(method, url)
    11. xhr.setRequestHeader("HTTP_X_REQUESTED_WITH", "XMLHttpRequest") //new
    12. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") //new
    13. xhr.onload = function() {
    14. const serverResponse = xhr.response
    15. console.log(serverResponse)
    16. const tweetsEl = document.getElementById("tweets")
    17. loadTweets(tweetsEl)
    18. }
    19. xhr.send(myFormData)
    20. }

    to test, runserver and input
    image.png
    the console:

    1. ajax True
  • we use a 201 status for ajax requests in /tweets/views.py

    1. def tweet_create_view(request, *args, **kwargs):
    2. # print("ajax", request.is_ajax())
    3. form = TweetForm(request.POST or None)
    4. print('post data is', request.POST)
    5. next_url = request.POST.get("next") or None
    6. if form.is_valid():
    7. obj = form.save(commit=False)
    8. obj.save()
    9. if request.is_ajax():
    10. return JsonResponse({}, status=201) # 201 == created items
    11. if next_url != None and is_safe_url(next_url, ALLOWED_HOSTS):
    12. return redirect(next_url)
    13. form = TweetForm()
    14. return render(request, 'components/form.html', context={"form" : form})

    to test, runserver and input:
    image.png
    so there is no server response in console log this time.

Serialize Django Model Object:

we don’t need to pick individuals elements but a serialized data model to handle

  • we write a serialize function in /tweets/models.py
  • (still apply random “likes” for now) ```python from django.db import models import random # new

class Tweet(models.Model):

  1. # id = models.AutoField(primary_key=True)
  2. content = models.TextField(blank=True, null=True)
  3. image = models.FileField(upload_to="images/", blank=True, null=True)
  4. def serialize(self): # new
  5. return {
  6. "id": self.id,
  7. "content": self.content,
  8. "likes": random.randint(0, 200)
  9. }
  1. - then apply serialize() to /tweets/views.py
  2. ```python
  3. def tweet_create_view(request, *args, **kwargs):
  4. form = TweetForm(request.POST or None)
  5. print('post data is', request.POST)
  6. next_url = request.POST.get("next") or None
  7. if form.is_valid():
  8. obj = form.save(commit=False)
  9. obj.save()
  10. if request.is_ajax():
  11. # return JsonResponse({}, status=201)
  12. return JsonResponse(obj.serialize(), status=201) # 201 == created items
  13. if next_url != None and is_safe_url(next_url, ALLOWED_HOSTS):
  14. return redirect(next_url)
  15. form = TweetForm()
  16. return render(request, 'components/form.html', context={"form" : form})
  17. # ...
  18. def tweet_list_view(request, *args, **kwargs):
  19. qs = Tweet.objects.all() # grab all objects in Tweet
  20. # tweets_list = [{"id" : x.id, "content" : x.content, "likes" : random.randint(0, 1000)} for x in qs]
  21. tweets_list = [x.serialize() for x in qs]
  22. data = {
  23. "isUser" : False,
  24. "response" : tweets_list
  25. }
  26. return JsonResponse(data)

to test, runserver and input
image.png
in the console, we get a serialized server response as our setting.

  • Rewrite the script part of home.html

    1. <script>
    2. function handleTweetCreateFormDidSubmit(event) {
    3. //..
    4. xhr.onload = function() {
    5. if (xhr.status === 201) { //if that's
    6. const newTweetJson = xhr.response
    7. console.log(newTweetJson.likes)
    8. const newTweetElement = formatTweetElement(newTweetJson)
    9. console.log(newTweetElement)
    10. tweetsContainerElement.prepend(newTweetElement) //prepend(add) newTweetElement before tweetsContainerElement
    11. }
    12. }
    13. xhr.send(myFormData)
    14. }
    15. //...
    16. //const tweetsEl = document.getElementById("tweets")
    17. const tweetsContainerElement = document.getElementById("tweets")
    18. //loadTweets(tweetsEl)
    19. loadTweets(tweetsContainerElement)
    20. //...
    21. </script>

    to test, runserver
    image.png
    so “likes” is undefined right now, and “newTweetElement” is “formattedTweet” string in formatTweetElement()
    but becasue loadTweets() also uses formatTweetElement() and lines under textarea includes “formattedTweet” string.
    undefined should be a random number, I forgot 2 lines in handleTweetCreateFormDidSubmit()