Search code examples
angularjsangularjs-scopeangularjs-ng-repeat

New object in Angular permanently binds to template element


I have a small Angular project which implements a Controller thusly:

concernsApp.factory('ConcernService', function ($http, $q) {
var api_url = "http://localhost:8000/api/";

var ConcernService = {

    ...

    save: function (url, obj) {
        console.log(obj)
        var defer = $q.defer();
        $http({method: 'POST',
            url: api_url + url,
            data: obj}).
            success(function (data, status, headers, config) {
                defer.resolve(data);
            }).error(function (data, status, headers, config) {
                defer.reject(status);
            });
        return defer.promise;
        },
    };
    return ConcernService;
});


concernsApp.controller('ProjectsCtrl', function ($scope, $http, ConcernService) {

    ...

    $scope.createProject = function(new_project) {
        ConcernService.save('projects/', new_project).then(function(){
            $scope.projects.push(new_project);
        });
    };

html template:

<div ng-controller="ProjectsCtrl" ng-init="getProjects(); getTasks(); new_project = {};">
    <div class="row col-lg-8">
      <h2>Projects</h2>
      <input type="text" ng-model="search_projects" class="form-control" style="width:300px; margin: 30px 0px">

      <table class="table table-bordered col-lg-8" ng-repeat="project in projects | orderBy: 'id' | limitTo: 10 | filter:search_projects">
        <tr>
            <td class="col-lg-4">
                <h3>{{ project.id }}</h3>
                <h4>{{ project.title }}</h4>
            </td>
            <td class="col-lg-2">
                <a href="#" ng-click="deleteProject(project)">Delete Project</a>
            </td>
        </tr>
      </table>
    </div>
   <div class="row">
     <div class="col-lg-8">
       <h2>Create a New Project</h2>
       <form class="form-horizontal">
         <div class="control-group">
           <label class="control-label" for="id_title">Title</label>
             <div class="controls">
               <input type="text" id="title" class="form-control" placeholder="Title" ng-model="new_project.title">
             </div>
           </div>
         </form>
        <br />
        <button class="btn btn-success" ng-click="createProject(new_project)">create</button>
     </div>
   </div>
 </div>

So, upon successful submission to the API, the code pushes the new_project object to the $scopes.projects, which works great. However, when I start typing in the create project title input field, it seems it is bound to the previous new project and the title of that project starts changing on the fly.

This also obviously stops any further new project object creation. I'm quite new to Angular and I'm not really sure what is going on here or how to solve it. Basically I want to keep creating new projects and pushing them to the array.


Solution

  • You are setting new_project = {} in ng-init, which happens only once when the directive is put in the DOM.

    In the createProject function, you can reset it to {} to make a new new_project.

    $scope.createProject = function(new_project) {
        ConcernService.save('projects/', new_project).then(function(){
            $scope.projects.push(new_project);
            $scope.new_project = {};
        });
    };
    

    As a sidenote, I would move the definition of new_project = {} to the controller as well.

    As a general Zen of Angular:

    Treat the scope as read only in the template and as a write only in the controller.