Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pre-populate current value of WTForms field in order to edit it

I have a form inside a modal that I use to edit a review on an item (a perfume). A perfume can have multiple reviews, and the reviews live in an array of nested documents, each one with its own _id.

I'm editing each particular review (in case an user wants to edit their review on the perfume once it's been submitted) by submitting the EditReviewForm to this edit_review route:

@reviews.route("/review", methods=["GET", "POST"])
@login_required
def edit_review():
    form = EditReviewForm()
    review_id = request.form.get("review_id")
    perfume_id = request.form.get("perfume_id")
    if form.validate_on_submit():
        mongo.db.perfumes.update(
            {"_id": ObjectId(perfume_id), <I edit my review here> })
        return redirect(url_for("perfumes.perfume", perfume_id=perfume_id))
    return redirect(url_for("perfumes.perfume", perfume_id=perfume_id))

And this route redirects to my perfume route, which shows the perfume and all the reviews it contains.

This is the perfume route:

@perfumes.route("/perfume/<perfume_id>", methods=["GET"])
def perfume(perfume_id):
    current_perfume = mongo.db.perfumes.find_one({"_id": ObjectId(perfume_id)})
    add_review_form = AddReviewForm()
    edit_review_form = EditReviewForm()
    cur = mongo.db.perfumes.aggregate(etc)
    edit_review_form.review.data = current_perfume['reviews'][0]['review_content']
    return render_template(
        "pages/perfume.html",
        title="Perfumes",
        cursor=cur,
        perfume=current_perfume,
        add_review_form=add_review_form,
        edit_review_form=edit_review_form
    )

My issue

To find a way to get the review _id in that process and have it in my perfume route, so I can pre-populate my EditReviewForm with the current value. Otherwise the form looks empty to the user editing their review.

By hardcoding an index (index [0] in this case):

edit_review_form.review.data = current_perfume['reviews'][0]['review_content']

I am indeed displaying current values, but of course the same value for all reviews, as the reviews are in a loop in the template, and I need to get the value each review_id has.

Is there a way to do this, before I give up with the idea of allowing users to edit their reviews? :D

Please do let me know if my question is clear or if there's more information needed.

Thanks so much in advance!!

UPDATE 2:

Trying to reduce further my current template situation to make it clearer:

The modal with the review is fired from perfume-reviews.html, from this button:

<div class="card-header">
    <button type="button" class="btn edit-review" data-perfume_id="{{perfume['_id']}}" data-review_id="{{review['_id']}}" data-toggle="modal" data-target="#editReviewPerfumeModal" id="editFormButton">Edit</button>
</div>

And that opens the modal where my form with the review is (the field in question is a textarea currently displaying a WYSIWYG from CKEditor:

<div class="modal-body">
    <form method=POST action="{{ url_for('reviews.edit_review') }}" id="form-edit-review">
        <div class="form-group" id="reviewContent">
            {{ edit_review_form.review(class="form-control ckeditor", placeholder="Review")}}
        </div>
    </form>
</div>

Currently this isn't working:

$(document).on("click", "#editFormButton", function (e) {
    var reviewText = $(this)
        .parents(div.card.container)
        .siblings("div#reviewContent")
        .children()
        .text();
    $("input#editReviewContent").val(reviewText);
});

and throws a ReferenceError: div is not defined.

Where am I failing here? (Perhaps in more than one place?)

UPDATE 3:

this is where the button opens the modal, and underneath it's where the review content displays:

<div class="card container">
    <div class="row">
        <div class="card-header col-9">
            <h5>{{review['reviewer'] }} said on {{ review.date_reviewed.strftime('%d-%m-%Y') }}</h5>
        </div>
        <div class="card-header col-3">
            <button type="button" class="btn btn-success btn-sm mt-2 edit-review float-right ml-2" data-perfume_id="{{perfume['_id']}}" data-review_id="{{review['_id']}}" data-toggle="modal" data-target="#editReviewPerfumeModal" id="editFormButton">Edit</button>
        </div>
    </div>
    <div class="p-3 row">
        <div class=" col-10" id="reviewContent">
            <li>{{ review['review_content'] | safe }}</li>
        </div>
    </div>
</div>
like image 219
Guillermo Brachetta Avatar asked May 24 '20 17:05

Guillermo Brachetta


Video Answer


1 Answers

You can do this with jQuery as when you open the form, the form will automatically show the review content in there. It will be done by manipulating the dom.

Also, add an id to your edit button, in this example, I have given it an id "editFormButton".

Similarly, add an id to the div in which review content lies so that it is easier to select, I have given it an id "reviewContent"

Similarly, add an id to edit_review_form.review like this edit_review_form.review(id='editReviewContent')

<script>
$(document).on("click", "#editFormButton", function (e) {
 var reviewText = $(this)
        .parents("div.row")
        .siblings("div.p-3.row")
        .children("div#reviewContent")
        .children()
        .text();
    $("input#editReviewContent").val(reviewText);
});
</script>

Don't forget to include jQuery.

Also, you can do it with pure javascript. You can easily search the above equivalents on google. This article is a good start!

like image 76
Kartikeya Sharma Avatar answered Nov 14 '22 22:11

Kartikeya Sharma