Show the template when the link is clicked using Angular directive

Perhaps the question is not phrased properly, but here is the idea I am working on.

I have a navbar set up with an array of countries that includes their names and coordinates.

<body>
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">Welcome to the world of directives!</a>
            </div>
            <ul class="nav navbar-nav">
                <li ng-repeat="countryTab in countries" ng-click="itemClicked(countryTab.label)" style="cursor:pointer">
                    <a>{{countryTab.label}}</a>
                    <country-tab-bar country="selectedCountry"></country-tab-bar>
                </li>
            </ul>
        </div>
    </nav>
    <script>
        var app = angular.module('app',[]);
        app.controller('appCtrl',function($scope){
            $scope.countries = [{
              id: 1,
              label: 'Italy',
              coords: '41.29246,12.5736108'
            }, {
              id: 2,
              label: 'Japan',
              coords: '37.4900318,136.4664008'
            }, {
              id: 3,
              label: 'USA',
              coords: '37.6,-95.665'
            }, {
              id: 4,
              label: 'India',
              coords: '20.5937,78.9629'
            }];
        });
    </script>

Now the country-tab-bar directive contains the template showing the name and map using the coordinates given in the array.

I attempted

    app.directive('countryTabBar',function(){
        return {
            restrict: 'E',
            scope:{
                country: '='
            },
            template: '<div>'+
            '   <div>Italy</div>'+
            '   <br/>'+
            '   <img ng-src="https://maps.googleapis.com/maps/api/staticmap?center={{country.coords}}&zoom=4&size=800x200"> '+        
            '</div>',
            link : function(scope,elem,attrs){
                scope.itemClicked = function(value){
                    scope.selectedCountry = value;
                }
            }
        }
    });

However, nothing happens when clicking on the country names.

The current UI layout is skewed.

https://i.sstatic.net/ewB5A.png

How can this be fixed? Suggestions are welcome. The map should only display after clicking a name, not before.

Answer №1

Your code just needed a few tweaks to get it working perfectly! Make sure to check the comments below for details.

View Working Fiddle Here

    //HTML
    <div ng-app="app">
      <div ng-controller='appCtrl'>
         <nav class="navbar navbar-default">
              <div class="container-fluid">
                  <div class="navbar-header">
                      <a class="navbar-brand" href="#">Welcome to the world of directives!</a>
                  </div>
                  <ul class="nav navbar-nav">
                      <!-- pass country to itemClicked function defined into controller -->
                      <li ng-repeat="country in countries" ng-click="itemClicked(country)" style="cursor:pointer">
                          <a>{{country.label}}</a>
                      </li>
                      <!-- directive moved outside the ng-repeat -->
                      <country-tab-bar country="selectedCountry"></country-tab-bar>
                  </ul>
              </div>
          </nav>
      <div>
    </div>

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

    //controller
    app.controller('appCtrl',function($scope){
        $scope.countries = [{
          id: 1,
          label: 'Italy',
          coords: '41.29246,12.5736108'
        }, {
          id: 2,
          label: 'Japan',
          coords: '37.4900318,136.4664008'
        }, {
          id: 3,
          label: 'USA',
          coords: '37.6,-95.665'
        }, {
          id: 4,
          label: 'India',
          coords: '20.5937,78.9629'
        }];

        // function to select the country (receive de full object as parameter)
        $scope.itemClicked = function(selected){
            // set the object needed by the directive
            $scope.selectedCountry = selected
        }

    });

    //directive
    app.directive('countryTabBar',function(){
    return {
        restrict: 'E',
        scope:{
            country: '='
        },
        template: '<div>'+
        '   <br/>'+
        '   <img ng-src="https://maps.googleapis.com/maps/api/staticmap?center={{country.coords}}&zoom=4&size=800x200"> '+        
        '</div>',
        link : function(scope,elem,attrs){

        }
    }
});

Answer №2

Deep within

Where exactly is the declaration of "selectedCountry" located?

I believe what you are attempting to achieve can be done like so:

<body>
    <nav class="navbar navbar-default">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand" href="#">Welcome to the world of directives!</a>
            </div>
            <ul class="nav navbar-nav">
                <li ng-repeat="countryTab in countries" ng-click="countryTab.showProperty = !countryTab.showProperty" style="cursor:pointer">
                    <a>{{countryTab.label}}</a>
                    <country-tab-bar country="countryTab" ng-show="countryTab.showProperty"></country-tab-bar>
                </li>
            </ul>
        </div>
    </nav>
    <script>
        var app = angular.module('app',[]);
        app.controller('appCtrl',function($scope){
            $scope.countries = [{
              id: 1,
              label: 'Italy',
              coords: '41.29246,12.5736108',
              showProperty: false
            }, {
              id: 2,
              label: 'Japan',
              coords: '37.4900318,136.4664008',
              showProperty: false
            }, {
              id: 3,
              label: 'USA',
              coords: '37.6,-95.665',
              showProperty: false
            }, {
              id: 4,
              label: 'India',
              coords: '20.5937,78.9629',
              showProperty: false
            }];
        });
    </script>


app.directive('countryTabBar',function(){
    return {
        restrict: 'E',
        scope:{
            country: '='
        },
        template: '<div>'+
        '   <div>Italy</div>'+
        '   <br/>'+
        '   <img ng-src="https://maps.googleapis.com/maps/api/staticmap?center={{country.coords}}&zoom=4&size=800x200"> '+        
        '</div>'
    }
});

Simply utilize the ng-show directive to hide all country-tab-bar elements, utilizing a new property that determines whether the tab should be shown or hidden.

The ng-click is applied to the li element containing both the button and the country-tab-bar itself. To only close it when clicking the button, move the ng-click directive inside the <a> element.

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

Setting the default value in a Reactive form on the fly: A step-by-step guide

When creating a table using looping, I need to set the default value of my Reactive Form to `Repeat` if the loop value matches a particular character, otherwise I want it to be empty. Here is my code: typescript rDefault:string = ""; create(){ ...

Displaying a custom error page in Next.js with the appropriate status code

I recently implemented a custom error page following the instructions provided in the documentation. My goal was to use this error page for specific errors that may occur during the getStaticProps function. Here's how I structured it: const Page: Next ...

Don't forget to save the toggleClass state to local storage in jQuery so it persists after

It's a challenge to maintain the value of toggleClass after refreshing or reloading the page. I have a structured table where rows toggle visibility when clicked. To preserve these toggle values, I utilized localStorage, but unfortunately, the state i ...

With Crypto-JS, a fresh hash is always generated

I'm looking to integrate crypto-js into my Angular 8 application. Here is a snippet of my code: import {Injectable} from '@angular/core'; import * as CryptoJS from 'crypto-js'; @Injectable() export class HprotoService { public ...

How can we incorporate SaxonJS higher-order functions into the Node.js runtime, separate from JS/HTML?

We are currently in the process of transitioning an older C# system that relied on custom functions to enhance XSLT processing. Our plan is to convert it to Node.js/saxon-js. After reviewing the documentation, it appears that while higher order functions ...

Angular2 only supports cross-origin requests for protocol schemes

I'm currently facing an issue while following the Angular Quickstart tutorial due to a CORS error. To resolve this, I made configurations in my Windows host file located under system32/drivers/etc/: 127.0.0.1 tour-of-heroes I also configured ...

Invoking a Vue method within a Laravel blade template

In my Laravel project, I have a blade that is loading a Vue component successfully. However, I am facing an issue where calling a method in the Vue component from a select box in the blade is not working as expected. Despite having a method call set up to ...

JQuery - Issue: Invalid syntax detected in the expression: #

I'm facing an issue with some tabs inside an accordion that don't seem to be functioning properly. The console is showing the following error: Error: Syntax error, unrecognized expression: # Despite searching for a solution online, I can&apos ...

Guide on setting up and customizing run.json within the latest JetBrains Fleet for Next.js

I've been attempting to set up input/output for the latest IDE from JetBrains, Fleet. However, I've hit a roadblock and can't seem to figure it out on my own. That's why I'm turning to the Stack Overflow community for help - how do ...

The Javascript Ajax loader gif is malfunctioning

I'm currently working on creating an Ajax loader gif using XMLHttpRequest. When I type something in the input field, a list of different words appears. This technique is commonly used in search engines as you type in the search box. However, I am als ...

The Art of Mass Updating Embedded Documents in MongoDB

Struggling with updating an embedded document in MongoDB using Bulk updates on version 3.0. Any assistance would be greatly appreciated. ...

Adjusting the content within a text area using an AngularJS service

I am currently editing text in a textarea within the admin view and I would like to display it through an angular service on the user view. However, I want the text to be displayed in multiple rows, maintaining the same format that I entered in the textare ...

Discover and capture zip codes using javascript

Looking to extract zip codes from strings like "HONOLULU HI 96814-2317 USA" and "HONOLULU HI 96814 USA" using JavaScript. Any suggestions on how to achieve this? ...

Showing the name of a class

Hello everyone, I have a piece of JavaScript code that generates HTML buttons when the page loads. The button attributes are fetched from a database through an ASP page. Everything is working fine except for displaying the class attribute - it shows as u ...

Instructions for creating a JavaScript click function that iterates through all records, not just the initial record

Although I'm new to web development and still learning the basics of html, javascript, etc., I have a problem that seems quite simple. The challenge lies in understanding javascript functions, which I find particularly tough to grasp. Here's what ...

What is the best way to replace multiple strings with bold formatting in JavaScript without losing the previous bolded text?

function boldKeywords(inputString, keywords){ for (var i = 0; i < keywords.length; i++) { var key = keywords[i]; if (key) inputString= inputString.replace(new RegExp(key, 'gi'), '<strong>' + ...

Challenges encountered when inserting nested data into MongoDB

I am currently in the process of constructing a database for a giveaway bot using MongoDB. When a new giveaway is initiated, the bot executes the following code to add the giveaway details to the database: const {mongoose} = require("mongoose") c ...

Having an issue with TypeScript and React where the onChange event on the <select> element is only setting the previous value instead of the current value when using the useState hook

I'm currently developing a scheduling web tool. One of the key features I'm working on involves calculating the total hours between two selected times, startTime and endTime. These times are chosen via a form and stored using the useState hook: ...

Issue with Javascript redirect not working following form submission in combination with Asp Classic

After countless hours of research and experimentation, I find myself at a standstill. My web page is coded extensively, so I'll do my best to provide a concise summary. The core elements of my ASP CLASSIC page for creating tickets via a form are as f ...

Saving resources with a promise in Angular

I am facing a challenge while trying to handle a promise from the angular $resource save function. According to the documentation, I should be able to access the raw $http promise by using the $promise property on the returned object. Here is an example: ...