Combining AngularJS, Google App Engine (GAE), and Endpoints

I've been working on integrating AngularJS with Google App Engine and endpoints. I have a small testing app with a basic API to help me understand how to use Angular with GAE endpoints. A user inputs text and clicks submit to send the entry to the back end. It functions well on Google's App Engine platform, but I'm facing difficulties with the client-side implementation. Any assistance would be greatly appreciated.

screenshot

https://i.sstatic.net/wpMDL.png

main.py

import webapp2
import settings
import endpoints

from protorpc import message_types
from protorpc import messages
from protorpc import remote

from google.appengine.api import users

class MainHandler(webapp2.RequestHandler):
  def get(self):
    self.response.write(render_template('base.html'))


class About(messages.Message):
about_x = messages.StringField(1)


@endpoints.api(name='cv', version='v1', description='yup yup yup')
class CvApi(remote.Service):

    @endpoints.method(
        About, 
        About,
        name='about.insert',
        path='about',
        http_method='POST')

    def insert_text(self, request):
        AboutModel(about_x=request.about_x).put()
        return request


api = endpoints.api_server([CvApi])

app = webapp2.WSGIApplication([
    ('/', MainHandler),

], debug=True)

base.html

<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <a class="brand" href="#">Colin Endpoints!</a>
            <div class="nav-collapse pull-right">
                <a href="javascript:void(0);" class="btn" id="signinButton">Sign in</a>
            </div>
        </div>
    </div>
</div>

<div class="container">
    <div id="myCtrl" ng-controller="myCtrl" >
        <form ng-submit="insert()">
            <div><h2>Grilla</h2></div>
            <div><textarea name="texto" ng-model="about_x"></textarea></div>
            <div><input id="post_this" type="submit" class="btn btn-small" value="Submit"></div>
        </form>
    </div>
</div>

<script src="https://apis.google.com/js/client.js?onload=init"></script>
<script type="text/javascript" src="/js/angular/controller.js"></script>
<script src="/lib/jquery/2.1.3/jquery.min.js"></script>

<script type="text/javascript" src="/lib/materialize/js/materialize.min.js"></script>
   

</body>

controller.js

var app = angular.module('colinmk', []);

app.config(['$interpolateProvider', function($interpolateProvider) {
  $interpolateProvider.startSymbol('<<');
  $interpolateProvider.endSymbol('>>');
}]);

app.controller('myCtrl', ['$scope', '$window', '$http',

  function($scope, $window, $http) {
    $scope.insert= function() {
      message = {
        "about_x" : $scope.about_x
      };
    };


  $window.init= function() {
    $scope.$apply($scope.load_cv_lib);
  };

  function init() {
    window.init();
  }

  $scope.load_cv_lib = function() {
    gapi.client.load('cv', 'v1', function() {
      $scope.is_backend_ready = true;
      $scope.insert();
    }, '/_ah/api');
  };
}]);

Answer №1

Well, it seems I made a mistake by forgetting to import and use the ndb module in my angularjs project. As a temporary solution, I decided to avoid using the google-client until I have a better understanding of how to implement it correctly. Instead, I have come up with a workaround by utilizing angular's ngResource dependency. I found a helpful example on GitHub that guided me in the right direction, which you can check out here.

main.py

import webapp2
import settings
import endpoints

from protorpc import message_types
from protorpc import messages
from protorpc import remote

from settings import render_template
from google.appengine.api import users
from google.appengine.ext import ndb

class MainHandler(webapp2.RequestHandler):
    def get(self):
        self.response.write(render_template('base.html'))

#for endpoint
class About(messages.Message):
    about_x = messages.StringField(1)

class AboutModel(ndb.Model):
    about_x = ndb.StringProperty()

@endpoints.api(name='cv', version='v1', description='yup yup yup')
class CvApi(remote.Service):

    @endpoints.method(
        About, 
        About,
        name='about.insert',
        path='about',
        http_method='POST')

    def insert_text(self, request):
        AboutModel(about_x=request.about_x).put()
        return request


api = endpoints.api_server([CvApi])

app = webapp2.WSGIApplication([
    ('/', MainHandler),

], debug=True)

base.html

<div class="container">
    <div id="myCtrl" ng-controller="myCtrl" >
        <form ng-submit="insert()">
            <div><h2>Grilla</h2></div>
            <div><textarea name="texto" ng-model="info"></textarea></div>
            <div><input id="post_this" type="submit" class="btn btn-small" value="Submit"></div>
        </form>
    </div>
</div>

controller.js

var app = angular.module('colinmk', ['ngResource']);

app.config(['$interpolateProvider', function($interpolateProvider) {
  $interpolateProvider.startSymbol('<<');
  $interpolateProvider.endSymbol('>>');
}]);

app.factory('apiResource', function($resource){
    var apiResource = $resource('/_ah/api/cv/v1/about', {
      save:   {method:'POST'}
      // query: {method: 'GET', isArray: false},
      // update: {method: 'PUT'}
    });
    return apiResource;
})

app.controller('myCtrl', ['$scope', 'apiResource',

  function($scope, apiResource) {

    $scope.insert = function() {
      $scope.about = [];
      var r = new apiResource();
      r.about_x = $scope.info;
      r.$save();
      $scope.about.push(r);
      $scope.info = '';
      console.log(r);
    };

}]);

Answer №2

Your code seems to be missing the actual call to the endpoint method. Make sure to include something like this:

gapi.client.cv.about(message).execute(function(resp) {
                    if (!resp.code) {
                        // Perform actions if successful
                    } else {
                        console.log(resp.code);
                    }
            });

This call should be in your insert function.

Also, remember to follow these steps first.

function loadGoogleClient() {
                    var script = document.createElement("script");
                    script.src = "https://apis.google.com/js/client.js?onload=init";
                    document.body.appendChild(script);
                }
                $(function() {
                    loadGoogleClient();
                });

Then, load your API:

function init() {

var endpoint = window.location.origin + '/_ah/api'; 
gapi.client.load('cv', 'v1', '', endpoint); // Callback function is the third argument  

}

Once these steps are completed, you can start calling methods from your API.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for dynamically resizing a div element as a user scrolls, allowing it to expand and contract based on

I was working on a project and everything seemed easy until I hit a roadblock. What I am trying to achieve is expanding a div to 100% when scrolling down to the bottom of the div, then shrink it back to 90% at the bottom and do the reverse when scrolling ...

Replicate the form to a new one while concealing the elements and then submit it

Initially, I was working with just one form. Now, I find myself in a situation where I need to utilize a different form which contains the same inputs. This is necessary because depending on the action taken upon submission, different processes will be tri ...

Changing Images with Button Click in Javascript

I am facing an issue with my buttons that should swap images once clicked. The first two buttons work perfectly, but for the third and fourth buttons, the images do not disappear when clicking another button. Below is the current code in the document head ...

Retrieving Files from POST Request Body Using Node.js and Angular

Currently, I am developing a MEAN Stack application and facing an issue while handling a form that should allow users to upload a file upon submission. The process seems to work seamlessly on the client side; however, when I inspect the request body after ...

Transition not influencing the scale property when activating a class

My modal is not scaling in and out properly when I toggle the 'active' class. It either fully scales out or scales in without any transition. Example: const openPopupButtons = document.querySelectorAll('[data-popup-target]'); const ...

The 'substr' property is not found in the type 'string | string[]'

Recently, I had a JavaScript code that was working fine. Now, I'm in the process of converting it to TypeScript. var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; if (ip.substr(0, 7) == "::ffff ...

The navigation bar in React Router is interfering with the loading of other components

Currently, I am in the process of setting up a simple navigation bar that consists of basic buttons without any complex functionality. However, I have encountered an issue where placing the navbar inside the switch prevents other components from loading ...

Exploring the Information Within HTML Forms

When my HTML form sends data to the server, it looks like this: { r1: [ '1', '2', '3' ], r2: [ 'Top', 'Greg', 'Andy' ], r3: [ 'validuser', 'invaliduser', 'validuser&a ...

React: An error has occurred - Properties cannot be read from an undefined value

THIS PROBLEM HAS BEEN RESOLVED. To see the solutions, scroll down or click here I've been working on a React project where I need to fetch JSON data from my server and render it using two functions. However, I'm encountering an issue where the v ...

Uh-oh! Angular 6 has encountered an unexpected error with template parsing

I am currently working on an Angular application where I have integrated the FormsModule from '@angular/forms' in my app.module.ts. However, despite this, I keep encountering the error message No provider for ControlContainer. Error log: Uncaug ...

The function of jQuery .click() not triggering on elements within msDropDown

I'm having difficulty implementing jQuery on an Adobe Business Catalyst site. The HTML snippet below shows the structure: <div class="banner-main"> <div class="banner-top"> <section class="banner"> <div class="catProd ...

Executing a series of AJAX requests within a loop

I am looking for a way to optimize sending multiple AJAX calls simultaneously in Javascript/Angular. Despite my efforts to find a solution, I have come up empty-handed. My goal is to send all requests as quickly as possible without waiting for each one to ...

XPages component retrieval function is malfunctioning

Utilizing an XPage with JQuery dialog and client-side validation adds efficiency to the user input process. However, there seems to be a disconnect between the client-side validation and server-side properties. Although the client-side validation functions ...

Transform the JSON response from MongoDB into a formatted string

var db = mongoose.connection; const FoundWarning = db.collection('warning').find({UserID: Warned.user.id, guildID: message.guild.id}).toArray(function(err, results) { console.log(results); }) I have been attempting to ...

Tips for accessing the value of a DOM node during the first render

I am attempting to extract a value from an input textbox during the initial rendering process using useRef, but I am encountering the following error: " ref is not a prop. Trying to access it will result in undefined being returned. If you need to ac ...

Enhance Your Website with Dynamic Autocomplete Feature Using jQuery and Multiple Input Search Functionality

I am working on a form with three input fields. Here is the HTML structure: Name<input type="text" class="customer_name" name="order[contact][first_name]"/><br/> Email<input type="text" class="customer_email" name="order[contact][email]"/& ...

Is it possible to delay Vue rules from validating until a user interacts with an element?

For a project I am working on, I have implemented a v-date-picker where users can select a departure date and a return date. Interestingly, while most of the input field validations only occur after user interaction, the departure date picker displays an e ...

IntelliJ has removed the connect-flash plugin, preventing me from reinstalling it

Learning node.js is new to me and I encountered a strange issue. While working on implementing login functionality with passportjs, I faced an error where req.flash() was not functioning properly. Oddly enough, it was working fine yesterday when I used it ...

Generate items above the mesh

I'm currently working on a procedural terrain generation project. I have successfully generated terrain using Perlin noise, and now I want to add procedural grass generation with some specific constraints. My goal is to only generate grass within a c ...

Execute asynchronous functions without pausing the thread using the await keyword

When working with an express route, I need to track a user's database access without: waiting for the process to complete before executing the user's task worrying about whether the logging operation was successful or not I'm uncertain if ...