Invoking a function from a higher-level parent scope within multiple layers of nested directives

I am working with a data structure that is nested infinitely. There is a top-level object containing a collection of objects, and each of these objects can also have their own collection of objects.

To iterate through this tree, I have implemented the following code:

collection.js

app.directive('collection', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      collection: '='
    },
    templateUrl: 'collection.html'
  };
});

collection.html

<ul>
  <member ng-repeat="member in collection" member="member"></member>
</ul>

member.js

app.directive('member', function($compile) {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      member: '='
    },
    templateUrl: 'member.html',
    link: function(scope, element, attrs) {
      var collection = '<collection collection="member.children"></collection>';

      if (scope.member.children) {
        $compile(collection)(scope, function(cloned, scope) {
          element.append(cloned);
        });
      }
    }
  };
});

member.html

<li>
  {{ member }} 
</li> 

index.html

<div data-ng-controller="collectionController">
  <collection collection="collection"></collection>
</div>

I am trying to enable clicking on a member at any level of nesting and setting the controller's selectedMember property as that member.

This is what I've attempted:

app.controller('collectionController', function($scope, collection) {

  collection.getCollection().then(function(collection) {
    $scope.collection = collection;
  });

  $scope.selectMember = function(member) {
    $scope.selectedMember = member;
  };

});

Since I need to call a function defined in the parent scope (the controller), I believe I need to pass down the selectMember function in the following way:

index.html

...
<collection collection="collection" select-member="selectMember"></collection>
...

collection.html

<member ng-repeat="member in collection" member="member" 
  select-member="selectMember()" ng-click="selectMember(member)">
</member>

collection.js

...
scope: {
  collection: '=',
  selectMember: '&selectMember'
}
...

member.js

...
scope: {
  member: '=',
  selectMember: '='
}
...

However, I'm facing issues getting the function to trigger correctly and set the controller scope's selectedMember property. The parameter passed to the selectMember function is undefined.

It seems like there might be a misunderstanding regarding scopes, complicated by the nested nature of the problem at hand.

Any suggestions or ideas would be greatly appreciated.

Edit: Here's a plunker: http://plnkr.co/edit/JfxpoLLgpADs9RXSMife

Answer №1

Absolutely, the approach you're taking seems to be on point - specifically passing the click handler from the outer scope. The only issue appears to be a slight confusion regarding how to pass the handler. It would have been helpful if you had created a plunker for reference, but I'll do my best to work through it blindly. :)

index.html

<collection collection="collection" select-member="selectMember(member)"></collection>

collection.html template

<member ng-repeat="item in collection" 
        member="item" 
        select-member="selectMember({member: member})"></member>

collection.js

...
scope: {
  collection: '=',
  selectMember: '&'
}
...

member.html template

<li ng-click="selectMember({member: member})>{{ member }}</li> 

Furthermore, when adding <collection> for member.children:

<collection collection="member.children" 
            select-member="selectMember({member: member})"></collection>

member.js

...
scope: {
  member: '=',
  selectMember: '&'
}
...

EDIT:

Well, this turned out to be more intricate than expected :) Nonetheless, it was an interesting challenge.

A few adjustments:

  1. The select-member attribute should not just "pass a function" as previously suggested.
  2. ng-click wasn't triggering correctly when placed on a member element - it was firing for both child and parent. I relocated it to the member.html template.
  3. For better clarity, I used item within the ng-repeat: ng-repeat="item in collection"

I am rectifying the code mentioned above. Additionally, I have crafted a version of your plunker.

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

Getting the value of elements with the same id in JavaScript can be achieved by utilizing the getElement

When I click on the first delete link, I want to display the value from the first input box. Similarly, when I click on the second delete link, I want to show the value from the second input box. Currently, it is always showing the value from the first del ...

What is the best way to categorize a collection of objects within a string based on their distinct properties?

I am working with an array of hundreds of objects in JavaScript, each object follows this structure : object1 = { objectClass : Car, parentClass : Vehicle, name : BMW } object2 = { objectClass : Bicycle, parentClass : Vehicle, name : Giant } object3 = { ob ...

AngularJS modal popup with a selectable table

Is there a way to open a modal popup containing a table in my application? I'm trying to achieve this by setting up an event in my app.js that triggers the modal when a row is clicked. Additionally, I need to update a field with the selected item&apos ...

Modifying the array structure will deselect all individual <Input> elements that have been iterated

Hoping to create a system for adding/removing sub-items with buttons that increment/decrement slots in an array, where input fields are automatically added and removed: <div *ngFor="let item of itemsInNewOrder; let i = index"> <input [(ngModel) ...

Viewing saved information prior to saving - JavaScript

I'm looking for a solution to allow users to preview captured records before they are inserted. Any suggestions on how to achieve this? HTML.html <form id="view" method="POST" class="formular"> <label>Name</label> ...

toggle back and forth between two div elements

I am trying to create a toggle effect between two divs, where clicking on one will change its border and header color to red while the other div disappears. I have tried using an IF statement in my JavaScript code, but it is not working as expected. Can so ...

Styling text using CSS depending on the displayed text

Utilizing Awesome Tables (AT), I am extracting data from a Google Sheets document to display on a website. The HTML template in the sheets is used for formatting the data, specifically focusing on the table output with inline CSS styling. Since the templat ...

Interact with Dialogflow using fulfillment to retrieve responses by opening an HTTP URL

Despite my efforts, I have yet to find a satisfactory solution. I am in the process of creating an agent on Dialogflow. This agent will be embedded on a webpage, not as part of Facebook Messenger or Google Assistant. The purpose of this agent is to guide ...

Step-by-step guide on resolving AngularJS Issue: [$injector:modulerr]

I'm encountering an issue with Angular JS where I'm receiving the following error: jquery.js:7993 Uncaught Error: [$injector:modulerr] Failed to instantiate module application due to: Error: [$injector:nomod] Module 'application' is no ...

Having trouble setting the `variant='dense'` for material-ui Toolbar – it remains at a height of 64px no matter what

Implemented a hello world AppBar/Toolbar with the variant='dense' style. import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import registerServiceWorker from './registerServiceWo ...

My goal is to prevent users from using the Backspace key within the input field

Let's say we want to prevent users from using the backspace key on an input field in this scenario. In our template, we pass the $event like so: <input (input)="onInput($event)"> Meanwhile, in our app.component.ts file, the function ...

When the jQuery document is ready, it typically returns null, but the console can still access and display

I have encountered an issue while working on a solution within a CMS (EPiServer). When I utilize console.log to check my object, it displays a null value. $(document).ready(function () { console.log("$('.EPiRequester').html() =" + $('. ...

What happens to the npm package if I transfer ownership of a github repository to a different user?

I was considering transferring a GitHub repository to another user or organization, but I have concerns about what will happen to older versions of the npm package associated with it. Let's say my Node.js package is named node-awesome-package. Versi ...

Utilizing Jquery Ajax to send a post request containing input values through Tampermonkey

I encountered an issue with my code - even though the logs in console show that it is working, I am unable to send the values to my server using AJAX post. jQ(document).on("keyup", "form input", function () { var value = jQ(this).val(); ...

An effective method for finding a key in a multi-dimensional array or object based on its value using JavaScript and/or jQuery

I have a unique object structure that resembles the following: var data = {}; data.items = { name : 'apple', price : '$1.00' }; data.products = { name : 'banana', price : '$0.50' }; data.goods = { name : 'oran ...

Unleashing the Power of v-model in Vue.js: A Comprehensive Guide to Referencing Input

I am a beginner in vue.js and I am currently facing an issue with making a get request from a field that has a v-model="embed.url" after pasting a link. The paste event works fine, but I'm struggling to reference the input with v-model="embed.url" and ...

Guide on utilizing fs.readStream and fs.writesream for transmitting and receiving video file (.mp4) either from server to client or vice versa using Node Js

## My Attempt to Receive and Save Video Stream in .mp4 Format ## ---------- > Setting up Server Side Code > Receiving Video stream from client and saving it as a .mp4 file var express = require('express'); var app = global.app = expor ...

Encounter a snag when attempting to upgrade to React version 16.10.2 while working with Ant Design Components - the error message reads: "

After upgrading to the latest React version 16.10.2, I encountered issues while using Ant Design Components. I specifically wanted to utilize the Title component from Typography. Here is an example of what I was trying to do: import { Typography } from & ...

Unusual Behavior in AngularJS: Using ng-include Triggers Full Page Reloading

An issue arises where a simple ng-include command causes the entire website to be printed recursively in a specific area of the page, ultimately crashing the browser. Even changing the path doesn't resolve the problem, suggesting that it's not ev ...

Updating values within an ng-repeat loop by using the ng-change directive to increment or decrement

Below is an example code snippet that demonstrates a checkbox feature: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Welcome to LearnKode - A code learning platform</title> ...