简体   繁体   中英

Angularjs form not submitting data

I'm creating a MEAN stack app and I've been using the book 'Mean Web Development' by Amos Q. Haviv to help me along. I've run into a problem where I have a form that is suppose to submit a recipe, but when I check the database the entry is there with an id, date and author but no title, mainImage, content, category or tags. I've been trying to figure it out on my own for the past couple of days and going over the book again to see if I made any mistakes, but no luck.

Here is my model:

// Load the module dependencies 
var mongoose = require('mongoose'),
    paginator = require('mongoose-paginator'),
    Schema = mongoose.Schema;

var CommentsSchema = new Schema({
    commentor: String,
    data: {
        type: Date,
        default: Date.now()
    },
    content:  {
        type: String,
        default: ' ',
        trim: true,
        required: "Enter a comment into the comment box"
    },
    agree: Number,
    disagree: Number
});

function toLower(lowerText) {
    return lowerText.toLowerCase();
}

var TagsSchema = new Schema({
    tags: {
        type: String,
        set: toLower
    }
});

var RecipeSchema = new Schema({
    created: {
        type: Date,
        default: Date.now()
    },
    author:  {
        type: Schema.ObjectId,
        ref: 'User'
    },
    title: {
        type: String,
        default: ' ',
        trim: true,
        required: 'Title cannot be blank'
    },
    mainImage: { 
        type: String,
        default: ' ',
        trim: true
    },
    content: {
        type: String, 
        default: ' ',
        trim: true,
        required: "Please enter recipe"
    },
    likes: Number,
    faves: Number,
    category: {
        type: String,
        set: toLower
    },
    tags: [TagsSchema],
    comments: [CommentsSchema]
});


// Use paginator
RecipeSchema.plugin(paginator, {
    limit: 20,
    defaultKey: '_id',
    direction: 1
});

mongoose.model('Recipe', RecipeSchema);

Here is my controller

// Load the module dependencies 
var mongoose = require('mongoose'),
    Recipe = mongoose.model('Recipe');

// Create a new error handling controller 
var getErrorMessage = function(err) {
    if (err.errors) {
        for (var errName in err.errors) {
            if (err.errors[errName].message) return err.errors[errName].message;
        }
    } else {
        return 'Unknown server error';
    }
};

// Create a new controller method that creates a new recipe
exports.create = function(req, res) {

    // Create  a new recipe object
    var recipe = new Recipe(req.body);

    // Set the recipe's 'author' property
    recipe.author = req.user;

    // Try saving the recipe
    recipe.save(function(err) {
        if (err) {
            // If an error occurs send the error message
            return res.status(400).send({
                message: getErrorMessage(err)
            });
        }else {
            // Send a JSON representation of the recipe
            res.json(recipe);
        }
    });
};

// Create a new controller method that retrieves a list of recipes
exports.list = function(req, res) {
    // User the model 'find' method to get a list of recipes
    Recipe.find().sort('-created').populate('author', 'username userName').exec(function(err, recipes) {
        if (err) {
            // If an error occurs send the error message
            return res.status(400).send({
                message: getErrorMessage(err)
            });
        } else {
            // Send a JSON representation of the article 
            res.json(recipes);
        }
    });
};

// Create a new controller method that returns an existing recipe
exports.read = function(req, res) {
    res.json(req.recipe);
}

// Create a new controller method that updates an existing recipe
exports.update = function(req, res) {
    // Get the recipe from the 'request' object
    var recipe = req.recipe;

    // Update the recipe fields
    recipe.title = req.body.title;
    recipe.mainImage = req.body.mainImage;
    recipe.content = req.body.content;
    recipe.category = req.body.category;
    recipe.tags = req.body.tags;

    // Try saving the updated recipe
    recipe.save(function(err) {
        if (err) {
            // If an error occurs send the error message
            return res.status(400).send({
                message: getErrorMessage(err)
            });
        } else {
            // Send a JSON representation of the recipe 
            res.json(recipe);
        }
    });
};

// Create a new controller method that deletes an existing recipe
exports.delete = function(req, res) {
    // Get the recipe from the 'request' object
    var recipe = req.recipe;

    // Use the model 'remove' method to delete the recipe
    recipe.remove(function(err) {
        if (err) {
            // If an error occurs send the error message
            return res.status(400).send({
                message: getErrorMessage(err)
            });
        } else {
            // Send a JSON representation of the recipe
            res.json(recipe);
        }
    });
};

// Create a new controller middleware that retrieves a single existing recipe
exports.recipeByID = function(req, res, next, id) {
    // Use the model 'findById' method to find a single recipe
    Recipe.findById(id).populate('author', 'username userName').exec(function(err, recipe) {
        if (err) return next(err);
        if (!recipe) return next(new Error('Failed to load recipe ' + id));

        // If an recipe is found use the 'request' object to pass it to the next middleware
        req.recipe = recipe;

        // Call the next middleware
        next();
    });
};

// Create a new controller middleware that is used to authorize an recipe operation 
exports.hasAuthorization = function(req, res, next) {
    // If the current user is not the author of the recipe send the appropriate error message
    if (req.recipe.author.id !== req.user.id) {
        return res.status(403).send({
            message: 'User is not authorized'
        });
    }

    // Call the next middleware
    next();
};

Here is express.js

// Load the module dependencies
var config = require('./config'),
    http = require('http'),
    express = require('express'),
    morgan = require('morgan'),
    compress = require('compression'),
    bodyParser = require('body-parser'),
    methodOverride = require('method-override'),
    session = require('express-session'),
    MongoStore = require('connect-mongo')(session),
    flash = require('connect-flash'),
    passport = require('passport');

// Define the Express configuration method
module.exports = function(db) {
    // Create a new Express appllication instance
    var app = express();

    // Create a new HTTP server
    var server = http.createServer(app);

    // Use the 'NDOE_ENV' variable to activate the 'morgan' logger or 'compress' middleware
    if (process.env.NODE_ENV === 'development') {
        app.use(morgan('dev'));
    } else if (process.env.NODE_ENV === 'production') {
        app.use(compress());
    }

    // Use the 'body-parser' and 'method-override' middleware functions
    app.use(bodyParser.urlencoded({
        extended: true
    }));    
    app.use(bodyParser.json({ type: 'application/*+json' }));
    app.use(methodOverride('X-HTTP-Method-Override'));

    // Configure the MongoDB session storage
    var mongoStore = new MongoStore({
        db: db.connection.db
    });

    // Configure the 'session' middleware
    app.use(session({
        saveUninitialized: true,
        resave: true,
        secret: config.sessionSecret
    }));

    // Set the application view engine and 'views' folder
    app.set('views', './app/views');
    app.set('view engine', 'ejs');

    // Configure the flash messages middleware
    app.use(flash());

    // Configure the Passport middleware
    app.use(passport.initialize());
    app.use(passport.session());

    // Load the routing files
    require('../app/routes/index.server.routes.js')(app);
    require('../app/routes/users.server.routes.js')(app);
    require('../app/routes/recipes.server.routes.js')(app);

    // Configure static file serving
    app.use(express.static('./public'));

    // Return the Server instance
    return server;
};

AngularJS recipes controller

// Invoke 'strict' JavaScript mode
'use strict';

// Create the 'recipes' controller
angular.module('recipes').controller('RecipesController', ['$scope', '$routeParams', '$location', 'Authentication', 'Recipe',
    function($scope, $routeParams, $location, Authentication, Recipe) {
        // Expose the Authentication service
        $scope.authentication = Authentication;

        // Create a new controller method for creating new recipes
        $scope.create = function() {
            // Use the form fields to create a new recipe $resource object
            var recipe = new Recipe({
                title: this.title,
                mainImage: this.mainImage,
                content: this.content,
                category: this.category,
                tags: this.tags
            });

            // Use the recipe '$save' method to send an appropriate POST request
            recipe.$save(function(response) {
                // If an recipe was created successfully, redirect the user to the recipe's page 
                $location.path('recipes/' + response._id);
            }, function(errorResponse) {
                // Otherwise, present the user with the error message
                $scope.error = errorResponse.data.message;
            });
        };

        // Create a new controller method for retrieving a list of recipes
        $scope.find = function() {
            // Use the recipe 'query' method to send an appropriate GET request
            $scope.recipes = Recipe.query();
        };

        // Create a new controller method for retrieving a single recipe
        $scope.findOne = function() {
            // Use the recipe 'get' method to send an appropriate GET request
            $scope.recipe = Recipe.get({
                recipeId: $routeParams.recipeId
            });
        };

        // Create a new controller method for updating a single recipe
        $scope.update = function() {
            // Use the recipe '$update' method to send an appropriate PUT request
            $scope.recipe.$update(function() {
                // If an recipe was updated successfully, redirect the user to the recipe's page 
                $location.path('recipes/' + $scope.recipe._id);
            }, function(errorResponse) {
                // Otherwise, present the user with the error message
                $scope.error = errorResponse.data.message;
            });
        };

        // Create a new controller method for deleting a single recipe
        $scope.delete = function(recipe) {
            // If an recipe was sent to the method, delete it
            if (recipe) {
                // Use the recipe '$remove' method to delete the recipe
                recipe.$remove(function() {
                    // Remove the recipe from the recipes list
                    for (var i in $scope.recipes) {
                        if ($scope.recipes[i] === recipe) {
                            $scope.recipes.splice(i, 1);
                        }
                    }
                });
            } else {
                // Otherwise, use the recipe '$remove' method to delete the recipe
                $scope.recipe.$remove(function() {
                    $location.path('recipes');
                });
            }
        };
    }
]);

And here is the form

<section data-ng-controller="RecipesController">    
    <div class="full-width-container">
        <div class="create-recipe">
            <div class="content">
                <form data-ng-submit="create()" novalidate>
                    <h1>Create A New Recipe</h1>
                    <label>Title</label>
                    <div>
                        <input type="text" data-ng-model="title" placeholder="Title" id="title" required />
                    </div>

                    <label>Main Image</label>
                    <div>
                        <input type="text" data-ng-model="mainImage" placeholder="Enter image url" id="mainImage" />
                    </div>

                    <label>Recipe</label>
                    <div>
                        <textarea data-ng-model="content" placeholder="Enter Recipe" id="content"></textarea>
                    </div>

                    <label>Category</label>
                    <div>
                        <input type="text" data-ng-model="category" placeholder="Available categories (Breakfast, Brunch, Lunch, Dinner)" id="category"/>
                    </div>

                    <label>Tags</label>
                    <div>
                        <input type="text" data-ng-model="tags" placeholder="Seperate tags by a comma" id="tags"/>
                    </div>

                    <div>
                        <input type="submit" value="Create" class="form-submit" />
                    </div>

                    <div data-ng-show="error">
                        <strong data-ng-bind="error"></strong>
                    </div>
                </form>
            </div>
        </div>
    </div>
</section>

Thanks for the suggestions, mcpDESIGNS. I tried of your suggestions, but still no luck. When I submit it goes through successfully like before, but still when I look at the database it's still empty with the exception of id, author and date. I don't know I'm implementing your suggestion correctly or not.

The first suggestion -

<section ng-controller="RecipesController"> 
    <div class="full-width-container">
        <div class="create-recipe">
            <div class="content">
                <form ng-submit="create(recipe)" novalidate>
                    <h1>Create A New Recipe</h1>
                    <label>Title</label>
                    <div>
                        <input type="text" ng-model"recipe.title" placeholder="Title" id="title" required />
                    </div>

                    <label>Main Image</label>
                    <div>
                        <input type="text" ng-model"recipe.mainImage" placeholder="Enter image url" id="mainImage" />
                    </div>

                    <label>Recipe</label>
                    <div>
                        <textarea ng-model"recipe.content" placeholder="Enter Recipe" id="content"></textarea>
                    </div>

                    <label>Category</label>
                    <div>
                        <input type="text" ng-model"recipe.category" placeholder="Available categories (Breakfast, Brunch, Lunch, Dinner)" id="category"/>
                    </div>

                    <label>Tags</label>
                    <div>
                        <input type="text" ng-model"recipe.tags" placeholder="Seperate tags by a comma" id="tags"/>
                    </div>

                    <div>
                        <input type="submit" value="Create" class="form-submit" />
                    </div>

                    <div ng-show="error">
                        <strong ng-bind="error"></strong>
                    </div>
                </form>
            </div>
        </div>
    </div>
</section>

The second suggestion -

// Invoke 'strict' JavaScript mode
'use strict';

// Create the 'recipes' controller
angular.module('recipes').controller('RecipesController', ['$scope', '$routeParams', '$location', 'Authentication', 'Recipe',
    function($scope, $routeParams, $location, Authentication, Recipe) {
        // Expose the Authentication service
        $scope.authentication = Authentication;

        // Create a new controller method for creating new recipes
        $scope.create = function() {
            // Use the form fields to create a new recipe $resource object
            var recipe = new Recipe({
                title: $scope.title,
                mainImage: $scope.mainImage,
                content: $scope.content,
                category: $scope.category,
                tags: $scope.tags
            });

            // Use the recipe '$save' method to send an appropriate POST request
            recipe.$save(function(response) {
                // If an recipe was created successfully, redirect the user to the recipe's page 
                $location.path('recipes/' + response._id);
            }, function(errorResponse) {
                // Otherwise, present the user with the error message
                $scope.error = errorResponse.data.message;
            });
        };

        // Create a new controller method for retrieving a list of recipes
        $scope.find = function() {
            // Use the recipe 'query' method to send an appropriate GET request
            $scope.recipes = Recipe.query();
        };

        // Create a new controller method for retrieving a single recipe
        $scope.findOne = function() {
            // Use the recipe 'get' method to send an appropriate GET request
            $scope.recipe = Recipe.get({
                recipeId: $routeParams.recipeId
            });
        };

        // Create a new controller method for updating a single recipe
        $scope.update = function() {
            // Use the recipe '$update' method to send an appropriate PUT request
            $scope.recipe.$update(function() {
                // If an recipe was updated successfully, redirect the user to the recipe's page 
                $location.path('recipes/' + $scope.recipe._id);
            }, function(errorResponse) {
                // Otherwise, present the user with the error message
                $scope.error = errorResponse.data.message;
            });
        };

        // Create a new controller method for deleting a single recipe
        $scope.delete = function(recipe) {
            // If an recipe was sent to the method, delete it
            if (recipe) {
                // Use the recipe '$remove' method to delete the recipe
                recipe.$remove(function() {
                    // Remove the recipe from the recipes list
                    for (var i in $scope.recipes) {
                        if ($scope.recipes[i] === recipe) {
                            $scope.recipes.splice(i, 1);
                        }
                    }
                });
            } else {
                // Otherwise, use the recipe '$remove' method to delete the recipe
                $scope.recipe.$remove(function() {
                    $location.path('recipes');
                });
            }
        };
    }
]);

Here is my recipes.server.routes.js

var users = require('../../app/controllers/users.server.controller'),
    recipes = require('../../app/controllers/recipes.server.controller');

var needsRole = function(role) {
  return function(req, res, next) {
    if (req.user && req.user.role === role)
      next();
    else
      res.status(401, 'Unauthorized');
  };
};

// Deine the routes 'module' method
module.exports = function(app) {

    // Setting the 'recipes' base routes
    app.route('/api/recipes')
        .get(recipes.list)
        .post(users.requiresLogin, needsRole("admin"), recipes.create);

    // Set up the 'recipes' parameterized routes
    app.route('/api/recipes/:recipeId') 
        .get(recipes.read)
        .put(users.requiresLogin, recipes.hasAuthorization, recipes.update)
        .delete(users.requiresLogin, recipes.hasAuthorization, recipes.delete);

        // Set up the 'recipeId' parameter middleware
        app.param('recipeId', recipes.recipeByID);
};

So from what I can see, the problem is in your $scope.create function.

In your function, you're creating your object that you want to send to the database, but the big problem is: this. Since you're creating a resource there, the this might be referring to something totally different, not your $scope .

You have 2 options, either change them all to:

title : $scope.title,
mainImage : $scope.mainImage, 
// etc

Or:

Try simply creating an object in your View of that entire form. For example:

<input ng-model="recipe.title" />
<input ng-model="reciple.mainImage" />
// etc

This way you can just pass the entire object to your ng-submit create(recipe) .

When you're in the controller you can then access each property of that object with recipe. , much easier. You could even pass that entire thing to your resource and let it map itself. new Recipe(recipe); for example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM