Monitoring a location within a grid using AngularJS

I have a question:

How can I track the position within a 10x10 grid in AngularJS and update it using arrow keys? Initially, I considered implementing this functionality in a directive with the following code:

angular.module('mymodule').directive('grid', function() {

    return {

        restrict : 'A',

        compile : function($target, $attrs) {

            var rows = $attrs.rows || 10;
            var cols = $attrs.cols || 10;

            for(var y = 0; y < rows; y++) {
                var row = angular.element('<div>');
                row.addClass('row');
                for(var x = 0; x < cols; x++) {
                    var col = angular.element('<div>');
                    col.addClass('item');
                    row.append(col);
                }
                $target.append(row);
            }

            return function($scope, $elem, $attrs) {
                // Code to manage position could go here
            }
        }

    }

});

While this code successfully creates the grid, I am unsure where to place the position management code. Additionally, I would like to be able to maintain positions across multiple grids. Would it be better to create a PositionManager to handle this task and store grid positions?

What are your thoughts on the best approach to integrating this functionality within my module?

Answer №1

Summary:
Interactive demo link (detailed but not extensively explained :D)


Due to length, the solution won't be fully copied here.
An overview and brief explanation of the approach will be provided.
(Full code available in the provided link, packaged as a module for easy usage.)


APPROACH

The solution involves the following key components:

  1. A grid directive
    Displays data in a visually pleasing grid and maintains a Grid object representation of the data/element.

  2. A gridContainer directive
    Acts as a container for multiple grids, ensuring only one grid is active at any given time.
    Arrow-key events are handled at this level, with proper delegation to the active grid.

  3. A Position service
    Used for creating and manipulating Position objects to track the active cell's position in a Grid.

  4. A Grid service
    Responsible for creating Grid objects that can track active-cell position, offer utility functions for movement, cell selection, determining focus movement after boundaries, etc.

  5. A GridContainer service
    Isolates grids, preventing navigation beyond container borders.
    Also enables multiple grids with the same ID as long as each resides in a different container.

  6. A DIRECTION constant
    Enumerates possible neighboring directions (North, South, East, West).

  7. Customized CSS
    Enhances grid appearance.

Functionality:

  1. Define a <grid-container> with nested <grid> elements.
    Specify essential data (IDs, sizes, data, positions, neighbors, etc).
    Each <grid-container> corresponds to a GridContainer object, and each <grid> to a Grid object.

  2. When the <grid-container> is focused and an arrow key is pressed, the active Grid's method is invoked (e.g., moveUp/Down/Left/Right).

  3. Grid calculates new position, adjusts internal representation.
    If new position exceeds boundaries, searches for a neighbor in that direction or wraps around if no registered neighbor.

  4. Clicking on a cell makes the parent Grid active with position shifted to the clicked cell.

Initiating and Template:

Example of 4-grid template:

<grid-container>
    <grid grid-id="grid-1" data="data1" width="{{data1[0].length}}" height="{{data1.length}}" x="0" y="0" neighbor-e="grid-2" neighbor-s="grid-3"></grid>
    ...
</grid-container>

Partial templates for grid and gridContainer directives:

grid-container.tmpl.html

<div tabindex="-1" ng-transclude=""></div>

grid.tmpl.html

<div class="grid"> ... (cell structure) ... </div>

Structure:

Outline of the code for brevity:

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

... Controllers, directives, services, etc ...

app.constant('DIRECTION', {...});

app.factory('Grid', function (Position, DIRECTION) {
    ...
});

app.factory('GridContainer', function (Grid) {
    ...
});

app.factory('Position', function () {
    ...
});

Find the complete code and demo here.

Module: esGrid is utilized, all components (controllers, directives, services) are es. namespace structured for reusability.
To implement:
1. Include the IIFE under [MODULE: esGrid] in a script.
2. Add esGrid as a dependency to your module.
3. Utilize directives in view:

<es-grid-container><es.grid ... ></es.grid>...<es-grid-container>

4. Customize the template:
<es.grid ... template-url="some.url"></es.grid>

5. Consider CSS referencing (escape . for special character): CSS: es\.grid { border: ... }


DISCLAIMER:
The solution may not fully support older browsers not in Angular 1.2.+ compatibility scope.
Works best with contemporary browsers; adaptable for older ones by revising functionalities like Array.forEach() to angular.forEach(), among other adjustments.

Answer №2

Using a compile function is not necessary in most cases and can be replaced with ng-repeat. Here is an example:

<div ng-repeat="row in ctrl.range(rows)">
    <span 
            ng-repeat="col in ctrl.range(cols)" 
            ng-class="{selected: ctrl.curRow === row && ctrl.curCol === col}">
        cell
    </span>
</div>

There are many ways to achieve the same result, but you can start with this example: http://jsfiddle.net/robianmcd/9otpqbg8/1/

You can navigate the grid by clicking on it and using arrow keys

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

What changes can be made to this function in order for the arches to be positioned directly in front of the camera?

I devised a method that arranges arches in front of a camera, side by side: <!-- HTML --> <a-curvedimage v-for="(value, index) in model" :theta-length="42" :rotation="setThumbsRotation(value, index)"> </a-curvedimage> <a-camera ...

AngularJS - Custom directive to extract a property value from an object

Currently, I am using the following for loop to retrieve the parent category: angular.forEach(queryTicketCategories, function(category) { if(category.id === $scope.ticketCategory.parentId) { $scope.parent = category; } }); I am looking fo ...

Why is 'this.contains' not recognized as a function when I invoke it within another function?

While attempting to create a Graph and incorporating one method at a time, I encountered an issue. Specifically, after calling a.contains("cats"), I received the error '//TypeError: Cannot read property 'length' of undefined'. Could thi ...

Preventing Internet Explorer from automatically scrolling to the top of the page when a new HTML element is dynamically inserted using

On my webpage, I have an ASP:Grid with a small copy button in each row to copy the text inside that cell. The javascript function I created for copying the text is as follows: var copyText = function (textToCopy) { $(".copy").append("<textarea id=&ap ...

Instructions for arranging dropdown options alphabetically with html, vue, and js

When working with JavaScript, is there a method to populate an options list from a database and then sort it alphabetically? ...

Inquiring about building a comprehensive AJAX website: SEO, Google index, design templates

I'm currently developing a fully AJAX-based website. My focus right now is on implementing page navigation and content display without the need for page reloading. Here's my approach: <html> <head> <!--CSS--> .hidde ...

What is the method to extract information from the provided URL?

Hello, I am looking to retrieve system requirements data from . How can I achieve this using JS or react? ...

When scrolling, use the .scrollTop() function which includes a conditional statement that

As a newcomer to jQuery, I've been making progress but have hit a roadblock with this code: $(window).scroll(function(){ var $header = $('#header'); var $st = $(this).scrollTop(); console.log($st); if ($st < 250) { ...

Issues with changes to AngularJS scope variables not appearing in multiple controllers

Within my AngularJS application, I am dealing with two controllers that utilize a shared variable referenced in the UI. The issue arises when I attempt to call the OpenPage method of NumTwoController from the UI, which updates the value of variable1. Subse ...

Looking to update the display of an array received in JSON format and then show it using ng-repeat?

Upon receiving a response from the backend, I am saving it in a variable called "allinfo" in my controller. The data received includes the name, date of birth, and hobby of a person. The hobby is an array that can contain any number of elements. In my vie ...

Utilizing AngularJS filtering for deep nested properties

I am looking to implement a filter on nested objects structured as follows: Object 1 : property1 property2 property3 children : Child 1 : propertyChild1 propertyChild2 Child 2 : The challenge I'm facing is t ...

Problems with Navbar rendering on multiple occasions

GENERAL INFO I've encountered an issue with the re-rendering of my sidemenu in Gatsby. Despite my efforts, I can't prevent the sidemenu from re-rendering and overriding the data that I set for it. const [activeParent, setActiveParent] = useState ...

Tricks for displaying a dynamic object tooltip in Three.js

Can anyone help me figure out how to create a HUD hint effect for a moving object? I envision something like this: An asteroid is floating through space, and when I click on it, a hint box with information pops up. I've been playing around with thi ...

What could be the reason for the malfunction of the select (mongoose query)?

I'm trying to retrieve a User's highest score post. To accomplish this, I am querying the Post model and looking for posts where their user._id matches the author in the post. Everything is functioning correctly in this regard. However, my goal ...

I require the capability to retrieve JSON data from beyond the confines of the function

After searching, I was unable to locate it. In my possession is a javascript file and a separate file named data.json. data.json { "today": [ { "id": 1, "title": "Note 1", "date": "21.05.2019", "text": "Lorem ipsum dolor sit ...

What is the best approach to determine the value of a textbox in an array for each row of

I am trying to display the total sum of values for each row in a data array. There are 5 rows of data, and I need to calculate the results for each one. Can someone assist me in solving this? function calculateTotalValue(){ var total = (document.get ...

Ajax UpdateProgress not functional

How can I resolve the issue where my AJAX UpdateProgress bar in ASP.NET is not running when executing a query in the correct format upon button click? Any solutions or help would be greatly appreciated. <html xmlns="http://www.w3.org/1999/xhtml"> ...

generate dynamic custom headers in an express application for accessibility by an Angular application

https://i.stack.imgur.com/6jyNE.pngRecently, I have started using Express and despite my extensive research, I haven't been able to find a solution to my issue. The problem is that I am receiving headers in my Express app, but when I attempt to make t ...

Prevent a dynamically generated text input from being used if it exceeds a specific character limit in VUE.JS

I am currently working on a Vue template that dynamically creates Bootstrap text inputs. The goal is to allow the user to retrieve the values onSubmit from these inputs. One requirement I have is to disable an input if the length of the text exceeds 10 ch ...

Issues with arguments not being identified - Discord.js version 14

After discovering that my arguments are no longer being recognized when executing a command, I encountered a strange issue. When args are not included, my console logs undefined, but if args are added, nothing is logged. This is snippet of my command hand ...