Ale Van Houtte
Ale Van Houtte

Reputation: 55

AngularJS show data from api in form to update it

im not sure the title explains clear enough what im trying to do, so im gonna try to explain here. i did the blog app from the book angularjs - from novice to ninja. because the api that the book uses is not working anymore, there were some functionalities i wasn't able to test. so later i did another tutorial of phalcon and build and api to do what the one in the angularjs book was supposed to. the api works fine (tested with postman, and also i use it for the login, so the blog app reaches it but i was only able to make it work in the login so far). so i have some doubts about the data i get from the api and how to show it in the for when i try to update one of the posts. so the services.js file is like this:

angular.module('spBlogger.admin.services', []).
factory('Post', ['$resource', 'API_ENDPOINT', function ($resource, API_ENDPOINT) {
    return $resource(API_ENDPOINT, {id:'@_id'}, {
        update: {
            method: 'PUT'
        }
    });
}]).
service('popupService', ['$window', function($window){
    this.showPopup = function(message){
        return $window.confirm(message); //Ask the users if they really want to delete the post entry
    }
}]).
value('API_ENDPOINT', 'http://testing-phalcon/api/posts/:id');

the controller.js file:

controller('PostUpdateController', ['$scope', 'Post', '$stateParams', function ($scope, Post, $stateParams) {
    console.log('in PostUpdateController');
    $scope.post = Post.get({id:$stateParams.id}); //Obtain the Post from backend. Search by Id
    console.log($scope.post);
    $scope.buttonText = "Update"; // Set initial label for button
    $scope.updatePost = function(){
        $scope.buttonText = "Updating. . ."; //Once clicked change button text
        $scope.post.$update(function(){
            $state.go('admin.postViewAll'); //Once updated go to state 'admin.postViewAll'
        });
    }
}])

the admin-update-post.html file that loads the form:

<div class="row">
    <div class="col-xs-8">
        <form name="postForm" ng-submit="updatePost()" class="form-horizontal" novalidate role="form">
            <div ng-include="'modules/admin/views/_form.html'"></div>
        </form>
    </div>
</div>

and finally the _form.html:

<div class="form-group" ng-class="{'has-error':postForm.title.$dirty && postForm.title.$invlaid}">
    <label for="title" class="col-sm-2 control-label">Post Title</label>
    <div class="col-sm-10">
        <input type="text" name="title" ng-model="post.title" ng-required="true" class="form-control" id="title" placeholder="Title">
        <span>Permalink:<i>/posts/[id]/{{post.title | permalink}}</i></span>
        <span class="error-message" ng-show="postForm.title.$dirty && postForm.title.$invalid">Title is mandatory</span>
    </div>
</div>
<div class="form-group" ng-class="{'has-error':postForm.content.$dirty && postForm.content.$invalid}">
    <label for="content" class="col-sm-2 control-label">Content</label>
    <div class="col-sm-10">
        <textarea cols="8" rows="6" name="content" class="form-control" ng-model="post.content" ng-required="true" id="content" placeholder="Content"></textarea>
        <span>{{post.content | wordcount}} words</span><br/>
        <span class="error-message" ng-show="postForm.content.$dirty && postForm.content.$invalid">You need to have some content!</span>
    </div>
</div>
<div class="form-group" ng-class="{'has-error':postForm.keywords.$dirty && postForm.keywords.$invalid}">
    <label for="keywords" class="col-sm-2 control-label">Keywords</label>
    <div class="col-sm-10">
        <input type="text" name="keywords" class="form-control" id="keywords" ng-pattern="/^[\w,]+$/" ng-model="post.keywords" placeholder="Comma separated keywords" />
        <span class="error-message" ng-show="postForm.keywords.$dirty && postForm.keywords.$invalid">Sorry! No special characters allowed here</span>
    </div>
</div>
<div class="form-group">
    <div class="col-sm-offset-2 col-sm-10">
        <button type="submit" class="btn btn-success" ng-disabled="postForm.$invalid">{{buttonText}}</button>
    </div>
</div>

What i want to achieve is that when i select a post that i want to update, i want to display the form with the data from the post in the title input, the content in the textarea, and the keywords in the keywords input. what i tried in the controller (forgive me if it looks bad, but im very new to angular) is:

$scope.thepost = {};
$scope.thepost.title = $scope.post.title;

but this obvioulsy doesn't work. i know the data is getting to the controller because of the console logs (i can see the api answers correctly), but im not sure first how to parse it and then how to pass it from the controller to the view. any help is welcome. thanks!

EDIT the template that displays all the posts available is admin-all-posts.html:

<div class="row">
    <div class="col-xs-8">
        <table class="table">
            <tr>
                <td><h3>View All Posts</h3></td>
                <td></td>
            </tr>
            <tr ng-repeat="post in posts | orderBy:'-_id'">
                <td>{{post.title}}</td>
                <td>
                    <a class="btn btn-primary" ui-sref="admin.postUpdate({id:post.id})">Edit</a>
                    <a class="btn btn-danger" ng-click="deletePost(post)">Delete</a>
                </td>
            </tr>
        </table>
    </div>
</div>

the controller that loads the posts from the api is in controllers.js:

controller('PostListController', ['$scope', 'Post', 'popupService', '$state', function ($scope, Post, popupService, $state) {
    $scope.posts = Post.query(); //Obtain all the posts from backend
    $scope.deletePost = function(post){
        if(popupService.showPopup('Really delete this?')){ //Ask for confirmation
            post.$delete(function(){
                $state.go('admin.postViewAll', undefined, { //once deleted reload the state
                    reload: true
                });
            });
        }
    }
}])

i hope this helps

Upvotes: 2

Views: 227

Answers (1)

georgeawg
georgeawg

Reputation: 48968

Examine the $scope.post after the data arrives from the server:

controller('PostUpdateController', ['$scope', 'Post', '$stateParams', function ($scope, Post, $stateParams) {
    console.log('in PostUpdateController');

    $scope.post = Post.get({id:$stateParams.id}); //Obtain the Post from backend. Search by Id
    ̶c̶o̶n̶s̶o̶l̶e̶.̶l̶o̶g̶(̶$̶s̶c̶o̶p̶e̶.̶p̶o̶s̶t̶)̶;̶
    $scope.post.$promise.then(function() {
        console.log($scope.post);
    }).catch(function(error) {
        console.log("ERROR:", error);
    });

    $scope.buttonText = "Update"; // Set initial label for button
    $scope.updatePost = function(){
        $scope.buttonText = "Updating. . ."; //Once clicked change button text
        $scope.post.$update(function(){
            $state.go('admin.postViewAll'); //Once updated go to state 'admin.postViewAll'
        });
    }
}])

It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.

Upvotes: 1

Related Questions