3

Am struggling hard to bind an array object with list of span values using watcher in Angularjs.

It is partially working, when i input span elements, an array automatically gets created for each span and when I remove any span element -> respective row from the existing array gets deleted and all the other rows gets realigned correctly(without disturbing the value and name).

The problem is when I remove a span element and reenter it using my input text, it is not getting added to my array. So, after removing one span element, and enter any new element - these new values are not getting appended to my array.

DemoCode fiddle link

What am I missing in my code?

How can I get reinserted spans to be appended to the existing array object without disturbing the values of leftover rows (name and values of array)?

Please note that values will get changed any time as per a chart.

This is the code am using:

<script>
    function rdCtrl($scope) {
        $scope.dataset_v1 = {};
        $scope.dataset_wc = {};
        $scope.$watch('dataset_wc', function (newVal) {
            //alert('columns changed :: ' + JSON.stringify($scope.dataset_wc, null, 2));
            $('#status').html(JSON.stringify($scope.dataset_wc));

        }, true);

        $(function () {
            $('#tags input').on('focusout', function () {
                var txt = this.value.replace(/[^a-zA-Z0-9\+\-\.\#]/g, ''); // allowed characters
                if (txt) {
                    //alert(txt);
                    $(this).before('<span class="tag">' + txt.toLowerCase() + '</span>');
                    var div = $("#tags");
                    var spans = div.find("span");
                    spans.each(function (i, elem) { // loop over each spans
                        $scope.dataset_v1["d" + i] = { // add the key for each object results in "d0, d1..n"
                            id: i, // gives the id as "0,1,2.....n"
                            name: $(elem).text(), // push the text of the span in the loop
                            value: 3
                        }
                    });
                    $("#assign").click();
                }
                this.value = "";
            }).on('keyup', function (e) {
                // if: comma,enter (delimit more keyCodes with | pipe)
                if (/(188|13)/.test(e.which)) $(this).focusout();
                if ($('#tags span').length == 7) {
                    document.getElementById('inptags').style.display = 'none';
                }
            });

            $('#tags').on('click', '.tag', function () {
                var tagrm = this.innerHTML;
                sk1 = $scope.dataset_wc;
                removeparent(sk1);
                filter($scope.dataset_v1, tagrm, 0);
                $(this).remove();
                document.getElementById('inptags').style.display = 'block';
                $("#assign").click();
            });
        });

        $scope.assign = function () {
            $scope.dataset_wc = $scope.dataset_v1;
        };

        function filter(arr, m, i) {
            if (i < arr.length) {
                if (arr[i].name === m) {
                    arr.splice(i, 1);
                    arr.forEach(function (val, index) {
                        val.id = index
                    });
                    return arr
                } else {
                    return filter(arr, m, i + 1)
                }
            } else {
                return m + " not found in array"
            }
        }

        function removeparent(d1)
        {
            dataset = d1;
            d_sk = [];
            Object.keys(dataset).forEach(function (key) {
                // Get the value from the object
                var value = dataset[key].value;
                d_sk.push(dataset[key]);
            });
            $scope.dataset_v1 = d_sk;
        }
     }
    </script>

Am giving another try, checking my luck on SO... I tried using another object to track the data while appending, but found difficult.

Satheesh Panduga
  • 818
  • 2
  • 13
  • 32
  • You'll have to "drop" jQuery mindset to do DOM manipulation when using angular or you'll just waste a lot of time on things like that... Look at http://ng-learn.org/2014/01/Dom-Manipulations/ – Chris Hermut Dec 08 '15 at 09:16
  • I __strongly__ recommend you to stop DOM manipulation using jQuery. Go through [“Thinking in AngularJS” if I have a jQuery background?](http://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background) – Satpal Dec 08 '15 at 09:17
  • 2
    Like @ChrisHermut said. Remove dom manipulation and use Angular's built-in UI. – itamar Dec 08 '15 at 09:19
  • @ChrisHermut '@Satpal .. Thanks a lot for your suggestions, I will go through the links you have provided! I just started off learning Angularjs and found watcher concept might suit as per my requirement, gave a try. – Satheesh Panduga Dec 08 '15 at 10:16

1 Answers1

1

You should be using the scope as a way to bridge the full array and the tags. use ng-repeat to show the tags, and use the input model to push it into the main array that's showing the tags. I got it started for you here: http://jsfiddle.net/d5ah88mh/9/

function rdCtrl($scope){
  $scope.dataset = [];
  $scope.inputVal = "";
  $scope.removeData = function(index){
    $scope.dataset.splice(index, 1);
    redoIndexes($scope.dataset);
  }
  $scope.addToData = function(){
    $scope.dataset.push(
      {"id": $scope.dataset.length+1,
       "name": $scope.inputVal,
      "value": 3}
    );
    $scope.inputVal = "";
    redoIndexes($scope.dataset);
  }
  function redoIndexes(dataset){
    for(i=0; i<dataset.length; i++){
      $scope.dataset[i].id = i;
    }
  }
}



<div ng-app>
<div ng-controller="rdCtrl">
   <div id="tags" style="border:none;width:370px;margin-left:300px;">
                    <span class="tag" style="padding:10px;background-color:#808080;margin-left:10px;margin-right:10px;" ng-repeat="data in dataset" id="4" ng-click="removeData($index)">{{data.name}}</span>
                    <div>
                        <input type="text" style="margin-left:-5px;" id="inptags" value="" placeholder="Add ur 5 main categories (enter ,)" ng-model="inputVal" />
                      <button type="submit" ng-click="addToData()">Submit</button>
                        <img src="../../../static/app/img/accept.png" ng-click="assign()" id="assign" style="cursor:pointer;display:none" />


                    </div>
           </div>

    <div id="status" style="margin-top:100px;"></div>
  </div>
</div>
itamar
  • 3,837
  • 5
  • 35
  • 60
  • Thanks a lot Itamar for your time.. I just started off with Angularjs, having no experience using it, I will try to find a way to get the thing done.. – Satheesh Panduga Dec 08 '15 at 10:06
  • is it OK if I implement remove tag function as I used in Jquery? – Satheesh Panduga Dec 08 '15 at 10:09
  • Is my requirement really complex? – Satheesh Panduga Dec 08 '15 at 10:09
  • I actually edited my answer to include a removeData() function that takes the $index of the ng-repeated items, and uses that to remove it from the dataset array - so that should work fine. – itamar Dec 08 '15 at 10:32
  • Your requirement is actually more or less the test every developer gets when they apply for a job - a to-do list :-) Copy-pasting my solution should give you the result you require. Would be great if you accepted my answer. – itamar Dec 08 '15 at 10:32
  • oh. ok :)... Thanks for letting me know.. Am new to Web development itself :) .. am into Business Intelligence. Started learning web technologies at the moment, its fun :) – Satheesh Panduga Dec 08 '15 at 10:39
  • How can I make my tag as a removeData button.. I mean, if I click on tag, it should be removed from the array(Row).. Right now, removeData function can be invoked via button, am not sure which will get deleted. Could you pls help me on that ? – Satheesh Panduga Dec 08 '15 at 10:46
  • Actually - the way I set it up above, the itself has an onclick that invokes the removeData($index) - so it already is that button. Welcome to web development and AngularJS - it's a fun world to be in :-) – itamar Dec 08 '15 at 10:48
  • Thank you so much @itamar.. Cant believe, I spent several hours and wrote so much of code in plain javascript and jquery-> to do this manually each activity .... I will learn Angularjs, its really interesting – Satheesh Panduga Dec 08 '15 at 10:56
  • It's fine - it's part of the process of learning. Just remember that when you're spending hours on an issue - the solution is probably simple. Take a 10 minute break and come back with fresh eyes and you'll solve it. Good luck! – itamar Dec 08 '15 at 10:57
  • Sorry, one last question.. when I add new spans and delete, id's in the array are not getting aligned (like 0,1,2,3..) is this something I should realign via javascript function ? – Satheesh Panduga Dec 08 '15 at 11:05
  • Oh - what are they doing? – itamar Dec 08 '15 at 11:11
  • I added a small function that runs after add or remove - that redoes the indexes just to be sure :-). – itamar Dec 08 '15 at 11:29
  • 1
    I couldn't just thank you for your time @itamar :) Its fortunate to have you involved in here today :) – Satheesh Panduga Dec 08 '15 at 11:36
  • Hi itamar, Could you please help me on http://stackoverflow.com/questions/34627360/svg-doesnt-get-created-for-d3-radar-chart-using-angularjs-javascript ? – Satheesh Panduga Jan 06 '16 at 07:09