How to access the parent array element in a nested ng-repeat in AngularJS

Hey there, I'm facing a bit of a puzzle with a seemingly simple question that's got me stumped.

In my code, I have a nested array structure:

$scope.rootItem = {
        id: '1',
        type: 'course',
        title: 'Adobe Photoshop CC for beginners',
        items: [{
            id: '2',
            type: 'label',
            title:'Label Title',
            items:[{
                id: '3',
                type: 'module',
                title:'Module title',
                items: [{
                    id: '4',
                    type: 'topic',
                    title:'Topic title',
                    items: [{
                        id: '5',
                        type: 'content',
                        title:'Content title'
                    }, {
                        id: '6',
                        type: 'content',
                        title:'Content title'
                    }]
                }]
            },{
                id: '7',
                type: 'resources',
                title:'Resources'
            },{
                id: '8',
                type: 'module',
                title:'Module title',
                items: [{
                    id: '9',
                    type: 'topic',
                    title:'Topic',
                    items: [{
                        id: '10',
                        type: 'question',
                        title:'Question title'
                    }]
                }, {
                    id: '11',
                    type: 'topic',
                    title:'Topic title',
                    items: [{
                        id: '12',
                        type: 'content',
                        title:'Content title'
                    }]
                }]
            }]
        },{
            id: '14',
            type: 'assessmentLabel',
            title: 'Assessment Label',
            items: [{
                id: '15',
                type: 'assessment',
                title: 'Assessment Title',
                items: [{
                    id: '16',
                    type: 'courseAssessment',
                    title: 'Course Assessment Question',
                    items: []
                }]
            }]
        }]
    };

This data is displayed using ng-repeat and everything works smoothly, including the sorting functionality implemented with ng-sortable (using JQuery UI Sortable).

Now, here's where I need your help - I'm trying to duplicate an item with ID: 5 using angular.copy().

The HTML setup:

<a href="" title="Duplicate Content" data-ng-click="duplicate(ngModelItem, $parent.ngModelItem.items)">
<span class="icon-duplicate"></span>
</a>

The duplication process seems to be working well, as I can pass the object to the function without any issues. However, when I attempt to push the duplicated object into its parent's array, I encounter a problem where $parent.ngModelItem.items is returning as undefined.

Here's the controller code:

$scope.duplicate = function(item, parent) {
        var itemCopy = angular.copy(item);

        parent.push(item);
    };

And this is how the HTML with ng-repeat looks like:

<ul class="apps-container" ui-sortable="sortableOptions" ng-model="ngModelItem.items" ng-class="ngModelItem.type">
            <li class="innerCont" ng-repeat="innerItem in ngModelItem.items">
                <tg-dynamic-directive ng-model="innerItem" tg-dynamic-directive-view="getView">
                </tg-dynamic-directive>
            </li>
        </ul>

Despite my attempts to pass the parent's ngModelItem.items (rootItem.items), it appears Angular has different ideas on how this should work. So, the big question remains - how can I successfully access the parent's ngModelItem.items array?

I would appreciate it if someone could explain why

{{$parent.$parent.ngModelItems.id}}
returns the correct parent ID, but when I try to pass that parent to the function like

data-ng-click="duplicate(parent.parent.ngModelItem.items)"

It doesn't seem to work as expected.

Below is the directive code snippet for reference:

angular.module('tg.dynamicDirective', [])
    .directive('tgDynamicDirective', ['$compile',
        function($compile) {
            'use strict';

            function templateUrlProvider(getView, ngModelItem) {
                if (getView) {
                    if (typeof getView === 'function') {
                        var templateUrl = getView(ngModelItem) || '';
                        if (templateUrl) {
                            return templateUrl;
                        }
                    } else if (typeof getView === 'string' && getView.length) {
                        return getView;
                    }
                }
                return '';
            }

            return {
                restrict: 'E',
                require: '^ngModel',
                scope: true,
                template: '<div ng-include="templateUrl"></div>',
                link: function(scope, element, attrs, ngModel) {

                    scope.$watch(function() {
                        var ngModelItem = scope.$eval(attrs.ngModel);
                        var getView = scope.$eval(attrs.tgDynamicDirectiveView);
                        scope.ngModelItem = ngModelItem;
                        return templateUrlProvider(getView, ngModelItem);
                    }, function(newValue, oldValue) {
                        scope.templateUrl = newValue;
                    });
                }
            };
        }
    ]);

Answer №1

After spending a few hours troubleshooting and researching various resources on $scope inheritance, I discovered that ng-if creates a new scope using prototypical inheritance. This was something I had not taken into consideration.

This realization prompted me to add an additional $parent when passing it to the function like this:

 data-ng-click="duplicate(ngModelItem, $parent.$parent.$parent.ngModelItem)"

In the controller, I then implemented the following solution:

$scope.duplicate = function(item, parent) {
        var itemCopy = angular.copy(item);
        var parentArray = parent.items;
        parentArray.push(itemCopy)
    };

I hope this information can help someone save valuable time and effort if they encounter a similar issue in the future.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating values in an array if they exceed a certain threshold

I'm facing a little issue with a straightforward concept. I have an array of data and would like to substitute each value if it exceeds a certain threshold, let's call it X. To tackle this problem, I devised a small script to illustrate the solu ...

Preserve selected option in select box after page refresh in JSP

I'm working on a jsp page that contains a simple select html element. Right now, when I select an option and click the Wyswietl button, the page refreshes, the table data is refreshed, but the selected option resets to default... How can I make it sta ...

Performing the AJAX request prior to the document being fully loaded

What I need is for an AJAX call to be made before the document is ready, and then use the response from the AJAX call to update certain HTML elements. This is what I currently have: var ajaxget = $.ajax({ type: 'GET', url:'/xxx ...

The total sum of values within labels that share the same class

I am attempting to sum up all the values of class tmpcpa and store the result in final_cpa, but for some reason final_cpa always ends up being 0. document.getElementById('cpa' + arr[0]).innerHTML = cpa + '(' + '<label id="tmp ...

using pointers as parameters to retrieve the length of a string

I have been experimenting with pointers based on the concepts from the K&R book. I developed a program that successfully swaps integers but encountered an issue with a function that calculates the length of a string using pointers. After compiling an ...

How to use jQuery to set a background image using CSS

I've been working on setting backgrounds dynamically with a jQuery script, but it seems like the .css function is not working as expected. Here's the code snippet: $(document).ready(function () { $(".VociMenuSportG").each(function () { ...

Employing various Class Methods based on the chosen target compiler option

Is there a way to instruct TypeScript to utilize different implementations of methods within the same class, based on the specified target option in the tsconfig.json file? I am currently transitioning one of my scripts to TypeScript to streamline managem ...

Utilize JavaScript, MySQL, and PHP to input data into a database

My JS function is supposed to make an ajax request, but for some reason it's not working. I've checked the URL in an alert and all variables are declared. var request = new XMLHttpRequest(); var url = "ajax_js/q_ajax.php?q="+ques+ ...

Addressing three visual problems with an html form input, dropdown menu, and clickable button

Currently, the output of my code looks like this: https://i.stack.imgur.com/pl5CJ.jpg The first box (squared) represents an <input>, while the second box (rectangled) is a <select>. There are several issues that I am facing: The text entered ...

Using the "this" keyword is required for an Angular Service-created function

Although this question leans more towards JavaScript than Angular, I encountered an issue while creating a service. The function call looked like this: // controller injects activityApi , then service function call is made var activities = activityApi.get ...

JS not functioning properly in specific pages causing display issues with page height set to 100%

I am facing an unusual issue where certain pages do not stretch to 100% page height in the middle section, causing the left-hand border to be incomplete. For example, on the 'Brentwood' site (please click on the 'Login' link in the top ...

Despite the presence of a producer and topic, sending Kafka messages is proving to be a challenge

Currently, I am using TypeScript and the KafkaJS library on my local machine with a single Kafka broker. After successfully connecting a producer, confirming the creation of my topic, and creating messages like so: const changeMessage = { key: id, ...

Is there a way to determine if an element has been scrolled past?

I am currently working on a script to detect when a specific element comes into view while scrolling. const targetElement = document.getElementById('sidebar'); window.addEventListener('scroll', () => { if (window.scrollY > tar ...

I'm encountering an issue with my React master component not being able to locate the

I am having trouble importing a component in my APP.js file. I have been attempting to bring MainComponent into the app.js component, but I am facing difficulties in fetching the component. Any assistance in resolving this issue would be greatly apprecia ...

What's preventing canvas from working offline but functioning properly on the TRYIT platform?

I have created some canvas-related code that works perfectly on TRYIT editor, but it fails to work locally when I copied the code into a file and tried to run it. This code is designed to take an image, set the width and height of a canvas based on that i ...

Ways to create a shorter upper line compared to the lower line (inside a div)

I'm dealing with an unordered list that has 3 list items, each represented by a green box containing an image and 3 divs (title, location, price). My main focus is on the title div of each box. If the title is long enough to span 2 lines, I need the ...

The AWS lambda function is experiencing difficulties with the AWS.HttpClient handleRequest operation

In my Node.Js lambda function, I am utilizing AWS HttpClient's handleRequest to search an ElasticSearch URL using the AWS SDK. I am following the guidelines provided in the AWS Documentation. Click here for more information on ES request signing. Pl ...

Error: The constructor for JsSHA is not valid for the TOTP generator

Attempting to create a TOTP generator similar to Google's timed-based authenticator using the React framework. I am utilizing the bellstrand module for TOTP generation, but I am encountering issues when trying to import it into my React code. Here is ...

Expanding a feature that modifies the CSS properties of every input element

Creating a text tracking (letter-spacing) demonstration where range sliders are used to update CSS properties. I'm looking to improve the functionality so that the labels also update dynamically, without repeating output2.textContent = this.value;. An ...

Is there someone who can explain to me the process behind this?

(function(ng, app){ app = angular.module('app', []); app.config(function($provide) { $provide.constant('town', 'Burlington'); }); app.constant('name', 'Rob F.'); app.controlle ...