How do I use angularjs to send a http PUT Request using an id

Question:

I have developed a Restful API in python that works with my database and table called groups. I have created script which allows me to GET & POST and I want to create script for PUT that will update a group. On my html document when you click on a group it populates the groups details on a form. On this form you should make any changes you need and then the script will use the group_id to send a PUT request to my server and store the update into my database.

groups.html

<!DOCTYPE html>
<html lang="en">
<head>
    <script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.7.5/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <link rel="stylesheet" href="stylesheet.css" />
    <meta charset="UTF-8">
    <title>Groups</title>
</head>
<body>

<div>
    <ul>
  <li><a class="active" href="index.html">Players</a></li>
  <li><a href="#news">Team</a></li>
  <li><a href="#contact">Manager</a></li>
  <li><a href="#about">Stadiums</a></li>
  <li><a href="">Matches</a></li>
  <li><a href="">Leaderboards</a> </li>
  <li><a href="">Groups</a></li>
    </ul>
</div>

<div class="row" ng-app = "app" ng-controller = "getGroups">
    <div class="column" >
        <h1>View Groups</h1>
    <table>
        <tr>
            <th>Group ID</th>
            <th>Group Name</th>
            <th>Team A</th>
            <th>Team B</th>
            <th>Team C</th>
            <th>Team D</th>
        </tr>
        <tbody ng-repeat = "groups in allGroups">
            <tr ng-repeat = "item in groups">
                <td ng-bind = "item.group_id"></td>
                <td ng-bind = "item.group_name"></td>
                <td ng-bind = "item.team_a"></td>
                <td ng-bind = "item.team_b"></td>
                <td ng-bind = "item.team_c"></td>
                <td ng-bind = "item.team_d"></td>
                <td><button ng-click="">Select Group</button></td>
                <td><button ng-click = "deleteGroup(item.group_id)">Delete Group</button></td>
            </tr>
        </tbody>
    </table>
    <br>
        </div>
<div class="column">
    <h1>Add New Group</h1>
    <form name = "addGroup" ng-submit = "submit()">
        <label>Group Name: </label><input type = "text" name = "Group Name" ng-model = "form.group_name"><br>
        <label>Team A: </label><input type = "text" name = "Team A" ng-model = "form.team_a"><br>
        <label>Team B: </label><input type = "text" name = "Team B" ng-model = "form.team_b"><br>
        <label>Team C: </label><input type = "text" name = "Team C" ng-model = "form.team_c"><br>
        <label>Team D: </label><input type = "text" name = "Team D" ng-model = "form.team_d"><br>
        <input type = "submit" value="Add New Group">
    </form>
    </div>

    <div class="column">
        <h1>Update Group</h1>
        <form class="data-form" name="updateGroup" ng-submit="updateGroups(update.group_id)">
            <label>Group ID</label><input type="text" name="Group ID" ng-model="update.group_id" readonly><br>
            <label>Group Name: </label><input type = "text" name = "Group Name" ng-model = "update.group_name"><br>
            <label>Team A: </label><input type = "text" name = "Team A" ng-model = "update.team_a"><br>
            <label>Team B: </label><input type = "text" name = "Team B" ng-model = "update.team_b"><br>
            <label>Team C: </label><input type = "text" name = "Team C" ng-model = "update.team_c"><br>
            <label>Team D: </label><input type = "text" name = "Team D" ng-model = "update.team_d"><br>
            <input type = "submit" value="Update Group">
        </form>

    </div>
</div>

<script>
    var app = angular.module('app',[]);

    app.controller('getGroups', function($scope, $http)
    {
        $http({
            method: "GET",
            url: "http://127.0.0.1:5000/api/v1/groups"
        }).then(function onSuccess(response) {
            $scope.allGroups = response.data;
        }, function error(response) {
            $scope.allGroups = response.statusText;
            alert("Something went wrong: Error No. 1")
        });

        $scope.submit = function()
        {
            $http({
                method: "POST",
                url: "http://127.0.0.1:5000/api/v1/groups",
                data: $scope.form,
                headers: { 'Content-Type' : 'application/json' }
            }).then(function onSuccess(response) {
                alert("Group has been added");
            }, function error() {
                alert("Something has gone wrong: Error No. 2");
            });
        };

        $scope.updateGroups = function(id)
        {
            $http({
                method: "PUT",
                url: ("http://127.0.0.1:5000/api/v1/groups/" + id),
                data: $scope.form,
            }).then(function onSuccess(response) {
                alert("Group has been added");
            }, function error() {
                alert("Opps")
            });
        };

        $scope.deleteGroup = function(id)
        {
            $http({
                method: "DELETE",
                url: ("http://127.0.0.1:5000/api/v1/groups/" + id),
            }).then(function onSuccess() {
                alert("Group has been deleted");
            }, function error() {
                alert("Something went wrong: Error No. 3");
            });
        };
    });

    $(document).ready(function () {
        $("td", this).on("click", function () {
            var tds = $(this).parents("tr").find("td");
            $.each(tds, function (i, v) {
                $($(".data-form input")[i]).val($(v).text());
            });

        });

    });
</script>

</body>
</html>

It is my $scope.updateGroups im having issue with, It should accept the id from the form and use that to store the updated details in the database

<form class="data-form" name="updateGroup" ng-submit="updateGroups(update.group_id)">
            <label>Group ID</label><input type="text" name="Group ID" ng-model="update.group_id" readonly><br>
            <label>Group Name: </label><input type = "text" name = "Group Name" ng-model = "update.group_name"><br>
            <label>Team A: </label><input type = "text" name = "Team A" ng-model = "update.team_a"><br>
            <label>Team B: </label><input type = "text" name = "Team B" ng-model = "update.team_b"><br>
            <label>Team C: </label><input type = "text" name = "Team C" ng-model = "update.team_c"><br>
            <label>Team D: </label><input type = "text" name = "Team D" ng-model = "update.team_d"><br>
            <input type = "submit" value="Update Group">
        </form>

And this is the function Im struggling to get working:

$scope.updateGroups = function(id)
        {
            $http({
                method: "PUT",
                url: ("http://127.0.0.1:5000/api/v1/groups/" + id),
                data: $scope.form,
            }).then(function onSuccess(response) {
                alert("Group has been added");
            }, function error() {
                alert("Opps")
            });
        };

I feel like im making a small error somewhere


VM201:1 OPTIONS 127.0.0.1:5000/api/v1/groups/undefined 404 (NOT FOUND)

I had an issue with CORS but I added code to my API – def after_request(response):

response.headers.add('Access-Control-Allow-Origin', '*') 
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') 
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response

Im getting this error in the console as well

Access to XMLHttpRequest at '127.0.0.1:5000/api/v1/groups/undefined' from origin 'localhost:63342' has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

But my GET, POST and DELETE are working as they should

My response headers are

Access-Control-Allow-Headers: Content-Type,Authorization
Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS 
Access-Control-Allow-Origin: *

Which I assumed should allow the PUT request to go through. But im getting a 404 error and the url is 127.0.0.1:5000/api/v1/groups/undefined which the undefined should be an id that is passed through the form.

My API.py file which contains my routes

# Import statements
import mysql.connector
from flask import Flask, abort, jsonify, request

# Global Constants
VERSION = 'v1'
BASE_URI = '/api/' + VERSION
GROUPS = '/groups'
GROUP = '/group'
URI_FOR_ALL_GROUPS = BASE_URI + GROUPS
MYSQL_USER = 'root'
MYSQL_PASS = ''
MYSQL_HOST = 'localhost'
MYSQL_DB = 'football'

# Creating an instance of Flask
app = Flask(__name__)


def create_connection():  # Method to Create Connection to Database
    return mysql.connector.connect(user=MYSQL_USER,
                                   password=MYSQL_PASS,
                                   host=MYSQL_HOST,
                                   database=MYSQL_DB)


# POST: Adding a new Group
@app.route(URI_FOR_ALL_GROUPS, methods=['POST'])
def add_group():
    # Method to add Group
    if not request.json:
        abort(400)
    conn = create_connection()
    cursor = conn.cursor()
    query = "INSERT INTO groups(group_name, team_a," 
            "team_b, team_c, team_d)" 
            "values (%s, %s, %s, %s, %s)"
    cursor.execute(query, (request.json['group_name'],
                           request.json['team_a'],
                           request.json['team_b'],
                           request.json['team_c'],
                           request.json['team_d']))
    id = cursor.lastrowid
    conn.commit()
    query = "SELECT * FROM groups WHERE group_id=" + str(id)
    cursor.execute(query)
    row = cursor.fetchone()
    group = {}
    for (key, value) in zip(cursor.description, row):
        group[key[0]] = value
    conn.close()

    return jsonify(group), 201


# GET: Get a single groups information
@app.route(URI_FOR_ALL_GROUPS + '/<int:id>', methods=['GET'])
def get_group(id):
    # Method to retrieve the information of a single group
    conn = create_connection()
    cursor = conn.cursor()
    query = "SELECT * FROM groups WHERE group_id=" + str(id)
    cursor.execute(query)
    row = cursor.fetchone()
    group = {}
    for (key, value) in zip(cursor.description, row):
        group[key[0]] = value
    conn.close()

    return jsonify(group), 200


# GET Retrieve all the groups
@app.route(URI_FOR_ALL_GROUPS, methods=['GET'])
def get_groups():
    # Method to retrieve all groups
    conn = create_connection()
    cursor = conn.cursor()
    query = "SELECT * FROM groups"
    cursor.execute(query)
    rows = cursor.fetchall()
    groups = []
    for row in rows:
        dict = {}
        for (key, value) in zip(cursor.description, row):
            dict[key[0]] = value
        groups.append(dict)
    conn.close()

    return jsonify({'groups': groups}), 200


# PUT: Updating a group
@app.route(URI_FOR_ALL_GROUPS + '/<int:id>', methods=['PUT'])
def update_group(id):
    # Method to update a group
    conn = create_connection()
    cursor = conn.cursor()
    query = "UPDATE groups SET group_name=%s, team_a=%s," 
            "team_b=%s, team_c=%s, team_d=%s " 
            "WHERE group_id=%s"
    cursor.execute(query, (request.json['group_name'],
                           request.json['team_a'],
                           request.json['team_b'],
                           request.json['team_c'],
                           request.json['team_d'], id))
    conn.commit()
    query = "SELECT * FROM groups WHERE group_id=" + str(id)
    cursor.execute(query)
    row = cursor.fetchone()
    group = {}
    for (key, value) in zip(cursor.description, row):
        group[key[0]] = value
    conn.close()

    return jsonify(group), 200


# DELETE: Deleting a group
@app.route(URI_FOR_ALL_GROUPS + '/<int:id>', methods=['DELETE'])
def delete_group(id):
    # Method to delete a single group
    conn = create_connection()
    cursor = conn.cursor()
    query = ("DELETE FROM groups WHERE group_id = %d" % id)
    cursor.execute(query)
    conn.commit()

    return jsonify('Group Deleted'), 200

@app.after_request
def after_request(response):
  response.headers.add('Access-Control-Allow-Origin', '*')
  response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
  return response


if __name__ == '__main__':
    app.run(debug=True)

This is the html and script code I use to delete a group

<tbody ng-repeat = "groups in allGroups">
            <tr ng-repeat = "item in groups">
                <td ng-bind = "item.group_id"></td>
                <td ng-bind = "item.group_name"></td>
                <td ng-bind = "item.team_a"></td>
                <td ng-bind = "item.team_b"></td>
                <td ng-bind = "item.team_c"></td>
                <td ng-bind = "item.team_d"></td>
                <td><button ng-click="">Select Group</button></td>
                <td><button ng-click = "deleteGroup(item.group_id)">Delete Group</button></td>

$scope.deleteGroup = function(id)
        {
            $http({
                method: "DELETE",
                url: ("http://127.0.0.1:5000/api/v1/groups/" + id),
            }).then(function onSuccess() {
                alert("Group has been deleted");
            }, function error() {
                alert("Something went wrong: Error No. 3");
            });
        };
Asked By: Alan

||

Answers:

That issue is triggered server-side.

Your Api is not allowing “undefined” to bind to your routing parameter. Try creating a vanilla “Foo” service, which just returns a 200. When you call it, I’m betting your PUT to that service goes through just fine.

After you can verify that your service layer supports HTTP PUT requests, you can focus in on why your client is not binding the parameter to the desired call correctly.

During that inspection of the client, you might want to set a breakpoint in your controller at the point update gets assigned its group_id. You did not provide it in your sample.


Now that you have provided more context, the client side issue appears to be related to you switching model references from item in your deleteGroup block to using update in your updateGroups block. If you change your ‘update’ references to instead refer to item I am confident you will change your results. For this to work for you though, you have to push the ‘update form into the repeater so that it can gain access to the appropriate group item which is being updated. At that point, I believe you will have your service call parameterizing correctly. Your view may not be what you want it to be after this change, but you’ll have to resolve that separately. To be clear, this is not the way I write angular code, so I’m not putting it out as an advisable approach to solving your problem (especially since I don’t know what problem you are trying to solve) but given the code you have provided, I believe that to be the crux of your binding problem.

Answered By: K. Alan Bates
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.