1

I need to save data(Save button) in local storage but before I must validate form. after invoking SavelocalStorage function have a mistake TypeError: Cannot read property '$valid' of undefined. what's wrong? any help appreciated

ps if $scope.myForm.$valid replace for myForm.$valid validation works but inappropriate way. even after fill in all the gaps still popup alert warning.

in case of removing data validation it is all right with LS data saving

var app = angular.module("myApp",['listOfBooks']);
            app.controller("myCtrl", function($scope){
                $scope.authors = [];

                $scope.addAuthor = function(){
                      var author = {};
                      author.surname = "";
                      author.name = "";
                      $scope.authors.push(author);
                };
                $scope.SavelocalStorage = function(){
                    if($scope.myForm.$valid){
                        localStorage.setItem('Authors', JSON.stringify($scope.authors));
                    }
                    else{
                        alert("fill in all the gaps pls!");
                    }
                };
            });
            
            var app = angular.module("listOfBooks", []);
        app.controller("booksCtrl", function($scope) {
          $scope.showBooks = false;
        
          $scope.currentAuthor = {};
          $scope.showBookList = function(author) {
            $scope.showBooks = !$scope.showBooks;
            $scope.currentAuthor = author;
          }
        
          $scope.addBook = function() {
           
            $scope.currentAuthor.books = $scope.currentAuthor.books || [];
            var book = {};
            book.title = "";
            $scope.currentAuthor.books.push(book);
          };
        });
<!DOCTYPE html>
<html>

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
  <link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
   
</head>

<body ng-app="myApp" ng-controller="myCtrl">
  <div class="container">
    <h3>AUTHORS' LIST</h3>
    <div class="btn-group">
      <button ng-click="addAuthor()" type="button" class="btn btn-default">Add</button>
      <button ng-click="SavelocalStorage()" type="button" class="btn btn-default">Save</button>
    </div>
    <form ng-controller="booksCtrl" name="myForm">
      <table class="table table-bordered">
        <tr>
          <th>Surname</th>
          <th>Name</th>
          <th>Books</th>
        </tr>
        <tr ng-repeat="author in authors">
          <td><input ng-model="author.surname" required type="text" class="form-control"></td>
          <td><input ng-model="author.name" required type="text" class="form-control"></td>
          <td>
            <button ng-click="showBookList(author)" type="button" class="btn btn-default">List</button>
          </td>
        </tr>
      </table>

      <div ng-show="showBooks" class="col-sm-8" style="background-color:lightblue; position: absolute; left:5px; top:5px;z-index:2;">
        <div class="btn-group">
          <button ng-click="addBook()" type="button" class="btn btn-default">Add</button>
        </div>
        <table class="table table-bordered">
          <tr>
            <th>Title</th>
          </tr>
          <tr ng-repeat="book in currentAuthor.books">
            <td><input ng-model="book.title" type="text" class="form-control"></td>
          </tr>
        </table>
        <button class="btn btn-sm btn-warning" ng-click="showBooks = false">Close</button>
      </div>
    </form>
  </div>
      </body>
</html>    

2
  • (had to confirm it in jsfiddle) your syntax with $scope.myForm is correct. However, the problem is that you have nested controllers. $scope.myForm is undefined because its form is in the child controller booksCtrl, while you are trying to access it from the outer controller myCtrl. Commented Dec 19, 2017 at 16:12
  • Do I have to move validation section to inner controller? Commented Dec 19, 2017 at 19:40

1 Answer 1

2

You need to play with $scope inheritance a little bit, When you use controllerAs syntax with the parent controller, If you set the name of form inside booksCtrl to vm.myForm, the form get registered to parent $scope because of prototypical inheritance of JavaScript, and you can call validation on the form in parent $scope.

var app = angular.module("myApp",['listOfBooks']);
            app.controller("myCtrl", function($scope){
                $scope.authors = [];
                var vm = this;
                $scope.addAuthor = function(){
                      var author = {};
                      author.surname = "";
                      author.name = "";
                      $scope.authors.push(author);
                };
                $scope.SavelocalStorage = function(){
                    if(vm.myForm.$valid){
                        localStorage.setItem('Authors', JSON.stringify($scope.authors));
                    }
                    else{
                        alert("fill in all the gaps pls!");
                    }
                };
            });
            
            var app = angular.module("listOfBooks", []);
        app.controller("booksCtrl", function($scope) {
          $scope.showBooks = false;
        
          $scope.currentAuthor = {};
          $scope.showBookList = function(author) {
            $scope.showBooks = !$scope.showBooks;
            $scope.currentAuthor = author;
          }
        
          $scope.addBook = function() {
           
            $scope.currentAuthor.books = $scope.currentAuthor.books || [];
            var book = {};
            book.title = "";
            $scope.currentAuthor.books.push(book);
          };
        });
<!DOCTYPE html>
<html>

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
  <link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
   
</head>

<body ng-app="myApp" ng-controller="myCtrl as vm">
  <div class="container">
    <h3>AUTHORS' LIST</h3>
    <div class="btn-group">
      <button ng-click="addAuthor()" type="button" class="btn btn-default">Add</button>
      <button ng-click="SavelocalStorage()" type="button" class="btn btn-default">Save</button>
    </div>
    <form ng-controller="booksCtrl" name="vm.myForm">
      <table class="table table-bordered">
        <tr>
          <th>Surname</th>
          <th>Name</th>
          <th>Books</th>
        </tr>
        <tr ng-repeat="author in authors">
          <td><input ng-model="author.surname" required type="text" class="form-control"></td>
          <td><input ng-model="author.name" required type="text" class="form-control"></td>
          <td>
            <button ng-click="showBookList(author)" type="button" class="btn btn-default">List</button>
          </td>
        </tr>
      </table>

      <div ng-show="showBooks" class="col-sm-8" style="background-color:lightblue; position: absolute; left:5px; top:5px;z-index:2;">
        <div class="btn-group">
          <button ng-click="addBook()" type="button" class="btn btn-default">Add</button>
        </div>
        <table class="table table-bordered">
          <tr>
            <th>Title</th>
          </tr>
          <tr ng-repeat="book in currentAuthor.books">
            <td><input ng-model="book.title" type="text" class="form-control"></td>
          </tr>
        </table>
        <button class="btn btn-sm btn-warning" ng-click="showBooks = false">Close</button>
      </div>
    </form>
  </div>
      </body>
</html>    

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.