Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS : Two-way binding between a textarea and ng-repeat-ed inputs

Tags:

angularjs

I was going to ask this as a question, but I figured out a solution. So at this point, I'm looking for a critique of my solution.

  1. I've got a static textarea, and an input with an ng-repeat directive.

  2. As the user types a sentence into the textarea, a input is rendered for each word in the sentence.

  3. Then if the user updates the text in any input, the corresponding word in the textarea sentence is updated (really the whole sentence is recreated).

Demo: http://plnkr.co/edit/bSjtOK?p=preview

Questions

Keeping in mind that I'm only 2 weeks into my AngularJS learning:

  • Did I write this in the "angular" way?
  • Is there something I could have done better?
  • Am I violating any no-nos?

Abbreviated Code

HTML

<textarea ng-model="sentence" ng-change="parseSentence()" style="width: 100%; height: 15em;"></textarea>

<input type="text" ng-repeat="w in words" ng-model="w.word" ng-change="buildSentance(w)" />

JavaScript

function WordCtrl($scope, debounce) {

    $scope.words = [];
    $scope.sentence = 'Hello there how are you today?';

    // this is called when the textarea is changed
    // it splits up the textarea's text and updates $scope.words 
    $scope.parseSentence = function() {

        var words = $scope.sentence.split(/\s+/g);
        var wordObjects = [];

        for (var i=0;i<words.length;i++) {          
          wordObjects.push({word: words[i]});
        }

        if ((words.length == 1) && (words[0] === '')) {
          $scope.words = [];
        } else {
          $scope.words = wordObjects;
        }

    };

    $scope.parseSentenceDebounced = debounce($scope.parseSentence, 1000, false);

    $scope.buildSentance = function(w) {

        var words = [];

        for (var i=0;i<$scope.words.length;i++) {
          var word = $scope.words[i].word;
          if (word.replace(/\s+/g,'') !== '') {
            words.push(word);
          }
        }

        $scope.sentence = words.join(' ');

        // if the user puts a space in the input
        // call parseSentence() to update $scope.words
        if (w.word.indexOf(' ') > -1) {
          $scope.parseSentenceDebounced();
        }

    }

    $scope.parseSentence();

}
like image 704
Walter Stabosz Avatar asked Apr 03 '13 20:04

Walter Stabosz


People also ask

What is two-way data binding in angular?

This page will walk through Angular two-way data binding and NgModel with examples. Using two-way binding, we can display a data property as well as update that property when user does changes.

What is the data-binding of HTML textarea element control with AngularJS?

Overview HTML textarea element control with AngularJS data-binding. The data-binding and validation properties of this element are exactly the same as those of the input element. Known Issues

What is the role of ngmodel directive in Angular 2?

So here the role of NgModel directive comes into the picture to work as bridge that enables two-way binding to HTML elements. It provides the required name pattern of target as ngModel in property binding and ngModelChange in event binding.

How to style <textarea> elements according to state in AngularJS?

Textarea elements are being referred to by using the value of the ng-model attribute. <textarea> elements inside an AngularJS application are given certain classes. These classes can be used to style textarea elements according to their state. ng-valid- key One key for each validation.


1 Answers

Interesting issue you are having. I put your code on my page and the first thing I noticed is that you cannot pass debounce in the controller method.

Next Problem I noticed is that you have an ng-change that changes the values on another box with ng-change. I changed the event to Keypress to stop the digest in a digest.

Here it is working in JSFiddle enter link description here

The code:

HTML

    <body ng-app="portal">
    <div ng-controller="WordCtrl">
    <textarea ng-model="sentence" ng-keypress="parseSentence()" style="width: 100%; height: 15em;"></textarea>
    <input type="text" ng-repeat="w in words" ng-model="w.word" ng-keypress="buildSentance(w)" />
    </div>
    </body>

Javascript

angular.module("portal",[]).controller("WordCtrl",function($scope) { 
    $scope.words = [];
    $scope.sentence = 'Hello there how are you today?';
    $scope.parseSentence = function () {
        var words = $scope.sentence.split(/\s+/g);
        var wordObjects = [];
        for (var i = 0; i < words.length; i++) {
            wordObjects.push({ word: words[i] });
        }
        if ((words.length == 1) && (words[0] === ''))
        {
            $scope.words = [];
        }
        else
        {
            $scope.words = angular.copy(wordObjects);
        }
    }

    $scope.buildSentance = function (w) {

        var words = [];

        for (var i = 0; i < $scope.words.length; i++) {
            var word = $scope.words[i].word;
            if (word.replace(/\s+/g, '') !== '') {
                words.push(word);
            }
        }

        $scope.sentence = words.join(' ');

        // if the user puts a space in the input
        // call parseSentence() to update $scope.words
        if (w.word.indexOf(' ') > -1) {
            $scope.parseSentenceDebounced();
        }
    }
    $scope.parseSentence();

    });

Hope this solves your issue.

like image 76
Jim Fallin Avatar answered Nov 15 '22 00:11

Jim Fallin