Nosail
Nosail

Reputation: 471

Unable to map element in an array to an input box in AngularJS

I am new to javascript and AngularJS. I'm having a bit of difficulty understanding why I am unable to edit elements in an array.

the foll is the JSON structure:

 [
    {
"name": "Wittgenstein",
"thoughts": ["thought 1", "thought 2", "thought 3"]

},

{
"name": "King",
"thoughts": ["thought 1", "thought 2", "thought 3"]

}
  ];

the foll is the plunker: plunker

whenever I click, the 'edit' button agst a thought, I want the text to show in the corresponding textbox, and then when I click 'save edit', the edit shld show in the list.

I think I've got it all messed up in my edit() method and i am somehow unable to wrap my head around it. any help wld be appreciated.

Upvotes: 2

Views: 308

Answers (5)

Arun Shinde
Arun Shinde

Reputation: 1185

Working Plunkr is here. https://plnkr.co/edit/l4CPe2JJ0U6JJ1YdooyV?p=preview

var app = angular.module('app', []);

app.controller('demoController', function($scope) {
    $scope.input = [];
    $scope.classifieds = [
           {
            "name": "Wittgenstein",
             "thoughts": ["thought 1", "thought 2", "thought 3"]

           },

           {
             "name": "King",
             "thoughts": ["thought 1", "thought 2", "thought 3"]

           }
     ];

       $scope.thoutEditIndex = null;
        /* Add */

        $scope.save = function(key, index) {
            console.log(key)
           console.log(index)
          $scope.classifieds[key].thoughts[$scope.thoutEditIndex] =               $scope.input[key];
          $scope.input[key] = '';
        $scope.thoutEditIndex = null;
      }


     /* Remove*/

    $scope.remove = function(classified, i) {
      classified.thoughts.splice(i, 1);
     $scope.thoutEditIndex = null;
   }

 /* Edit */

  $scope.edit = function(classified, key, index) {
    $scope.editing = true;
   console.log(classified)
   $scope.input[key] = classified.thoughts[index];
    $scope.editing = false;
   $scope.thoutEditIndex = index
 }


});

Upvotes: 1

Rakesh
Rakesh

Reputation: 61

You have nested ng-repeats in your scenario. In such a situation, you have to be careful with the use of $index. I recommend using the following syntax

ng-repeat = (key,value) in data

So in your scenario, use the following:

<div ng-repeat="(cIndex, classified) in classifieds">
...
    <li ng-repeat="(tIndex, thought) in classified.thoughts">

You will also have to change how you initialize your $scope.input model. Initialize it with same number of entries as number of classifieds (angular will not append an array element automatically for you). You can do this in the script file.

Also in your edit function, you were using classified.thought. This is not right as there is no thought property on the classified object (rather it is thoughts). I think you want to access the current thought associated with the list item. For this, you can additionally pass in the thought or tIndex as an additional parameter and use it accordingly.

Upvotes: 2

Arun P Johny
Arun P Johny

Reputation: 388446

Try with an editor variable to store the state in each iteration

var app = angular.module('my-app', [], function() {})

app.controller('demoController', function($scope) {

  $scope.input = [];

  $scope.classifieds = [{
    "name": "Wittgenstein",
    "thoughts": ["thought 1", "thought 2", "thought 3"]
  }, {
    "name": "King",
    "thoughts": ["thought 1", "thought 2", "thought 3"]
  }];


  /* Add */

  $scope.save = function(classified, editor) {
    classified.thoughts.push(editor.input);
    editor.input = '';
  }


  /* Remove*/

  $scope.remove = function(classified, i) {
    classified.thoughts.splice(i, 1);
  }

  /* Edit */

  $scope.edit = function(classified, index, editor) {
    editor.input = classified.thoughts[index];
    editor.index = index;
  }
  $scope.saveEdit = function(classified, editor) {
    classified.thoughts[editor.index] = editor.input;
    editor.index = -1;
    editor.input = '';
  }
});
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<div ng-app="my-app">
  <div ng-controller="demoController">
    <div ng-repeat="classified in classifieds">
      <h1>{{classified.name }}</h1>
      <ul>
        <li ng-repeat="thought in classified.thoughts">
          {{ thought }}
          <button ng-click="remove(classified, $index)">Remove</button>
          <button ng-click="edit(classified, $index, editor)">Edit</button>
        </li>
      </ul>
      <input ng-init="editor={index:-1}" type="text" ng-model="editor.input">
      <button type="submit" ng-if="editor.index==-1" ng-click="save(classified, editor)">Save</button>
      <button type="submit" ng-if="editor.index>-1" ng-click="saveEdit(classified, editor)">Save Edit</button>
    </div>
  </div>
</div>

Upvotes: 2

Gene
Gene

Reputation: 616

I forked the Plunker and made some improvements to make the code more readable, in particular making the edit state more transparent and hiding editing controls when not in edit mode.

The main problems were:

  • Not managing editing state clearly.
  • Not referring to the correct index in the outer ng-repeat $parent.$index is required.

Hope it helps.

Plunker Here Code Below:

view.html

<body ng-controller="demoController">
    editing {{editing}}
    <div ng-repeat="classified in classifieds">
      <h1>{{classified.name }}</h1>
      <ul>
        <li ng-repeat="thought in classified.thoughts">
          {{ thought }} <button ng-click="remove(classified, $index)">Remove</button><button ng-click="edit($parent.$index, $index)">Edit</button>
        </li>
      </ul>
      <div ng-show="editing[$index].editing">
        <input type="text" ng-model="editing[$index].thought">
        <button type="submit"  ng-click="save($index)">Save</button>
      </div>
    </div>

Controller.js

// Code goes here
var app = angular.module('app', []);

app.controller('demoController', function($scope) {

  $scope.input = [];
  $scope.editing = {};

  $scope.classifieds = [
    {
"name": "Wittgenstein",
"thoughts": ["thought 1", "thought 2", "thought 3"]

},

{
"name": "King",
"thoughts": ["thought 1", "thought 2", "thought 3"]

}
  ];


  /* Add */

  $scope.save = function(classifiedIndex) {
    var editingMeta = $scope.editing[classifiedIndex];
    var thoughtIndex = editingMeta.thoughtIndex;
    $scope.classifieds[classifiedIndex].thoughts[thoughtIndex] = editingMeta.thought;
    delete $scope.editing[classifiedIndex];
  }


  /* Remove*/

  $scope.remove = function(classified, i) {
    $scope.classified.thoughts.splice(i, 1);
  }

  /* Edit */

  $scope.edit = function(classifiedIndex, thoughtIndex) {
    var classified = $scope.classifieds[classifiedIndex];
    $scope.editing[classifiedIndex] = {
      editing: true,
      thoughtIndex: thoughtIndex,
      thought: classified.thoughts[thoughtIndex]
    }
  }


});

Upvotes: 3

Charlie
Charlie

Reputation: 23858

Your understanding is good.

Your problem here is that you need to pass both the classified index and the though index to your edit function in your child ng-repeat.

<li ng-repeat="thought in classified.thoughts">
          {{ thought }} 
    <button ng-click="remove(classified, $index)">Remove</button>
    <button ng-click="edit(classified, $index, classifides.indexOf(classified))">Edit</button>
</li>

This way the function know both the indexes of your classified and the thought in it. And change the function this way.

$scope.edit = function(classified, i, classifiedIndex) {

    $scope.editing = true;
    $scope.input[classifiedIndex] = classified.thoughts[i];
    $scope.editing = false;

  }

Upvotes: 1

Related Questions