Unique Options to Enhance Your AngularJS Directive

I've been attempting to pass dynamic variables into a directive that showcases a time picker (using pickadate.js: ). However, I'm facing challenges in getting these options into the directive. Despite searching extensively online, I am overwhelmed by the different approaches available and struggling to make it work correctly. Below is my current code:

Directive:

// Directive for selecting time on an HTML element
appDirectives.directive('pickATime', function() {
    return {
        // Attribute restriction
        restrict: 'A',
        // Link function for updating the DOM
        link: function(scope, element, attrs) {
            element.pickatime(scope.$eval(attrs.pickATime));
        },
        scope: {
            timeOptions: '=options'
        },
        templateUrl: '../Templates/timeoptions.html'
    };
});

Directive Template:

Min: {{timeOptions.startTime}} Max: {{customerInfo.endTime}}

HTML:

<input type="text" placeholder="Start Time" id="timestart" pick-a-time options="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

Controller with dynamic values from REST:

// Query settings from REST
appSettings.query(function(settings) {
    var setting = settings.value;

    angular.forEach(setting, function(settingvalue, settingkey) {
        if (settingvalue.Title == 'Active') {

            workDuration = settingvalue.Work_x0020_Day_x0020_Hours_x0020;
            nonWorkDuration = settingvalue.Non_x0020_Work_x0020_Day_x0020_H;

            var startHour = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[0];
            var startMinute = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[1];
            var startTime = '[' + startHour + ',' + startMinute + ']';
            var endHour = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[0];
            var endMinute = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[1];    
            var endTime = '[' + endHour + ',' + endMinute + ']';
            $scope.timeRange = {min: startTime, max: endTime};                  
        }
    })
});

A static method working on an input:

<input type="text" placeholder="End Time" id="timeend" pick-a-time="{min: [0,0], max: [23,30]}" data-ng-model="itemtimeend"class="form-control" autocomplete="off">

Update: After adjusting with Dave's help, the timeRange logs correctly but timeOptions in the directive shows as undefined.

Directive (timeOptions undefined in logging):

appDirectives.directive('pickATime', function() {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        element.pickatime(scope.pickATime);
        console.log("time options log" + scope.timeOptions);
    },
    scope: {
        timeOptions: '='

    },
    templateUrl: '../Templates/timeoptions.html'
};

});

Template:

min: {{timeOptions.min}}, max: {{timeOptions.max}}

Controller (logging correctly):

// Get $scope variables to control time picker range
var startHour = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[0];
var startMinute = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[1];
var startTime = '[' + startHour + ',' + startMinute + ']';
var endHour = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[0];
var endMinute = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[1];
var endTime = '[' + endHour + ',' + endMinute + ']';
$scope.timeRange = {
    min: startTime,
    max: endTime
};

HTML:

<input type="text" placeholder="Start Time" id="timestart" pick-a-time timeOptions="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

Update - Picker Working... but Now Form is not Submitting Time Data: details can be found in this Post: TimePicker directive won't submit time (undefined)

Special thanks to @dave-alperovich and @joe-enzminger for their invaluable assistance and insightful responses.

Controller:

// Get $scope variables to control time picker range
var startHour = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[0];
var startMinute = settingvalue.Work_x0020_Day_x0020_Start_x0020.split(":")[1];
var endHour = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[0];
var endMinute = settingvalue.Work_x0020_Day_x0020_End_x0020_M.split(":")[1];
$scope.timeRange = {
min: [startHour,startMinute],
max: [endHour,endMinute]
};

Directive:

appDirectives.directive('pickATime', function() {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        element.pickatime(scope.options());
    },
    scope: {
        options: '&pickATime'
    },
};
});

Usage:

<input ng-if="timeRange" type="text" placeholder="Start Time" id="timestart" pick-a-time="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

Answer №1

There are numerous strategies for transferring data from a parent scope to a directive. You have wisely opted for the isolated scopes approach, as shown by the

scope: {
}

declaration in your directive. This ensures that your directive's scope does not inherit prototypically from the parent scope.

The issue with your initial example is that the line:

element.pickatime(scope.$eval(attrs.pickATime));

results in passing undefined to the element.pickatime() function.

This happens because this particular line of code tries to evaluate the expression (which is a string) within the value of the pick-a-time HTML attribute in your DOM against the directive's scope. In your first example, the pick-a-time attribute's value is an empty string.

By using the non-dynamic version, where the pick-a-time attribute's value is now the string

"{min: [0,0], max: [23,30]}"

which is a valid Angular expression, $eval will return an object with min and max properties set accordingly, making your directive functional.

In both cases, your directive overlooks the value passed through the options attribute.

An easy solution would be to adjust your directive to utilize the data provided via the options attribute. Within your current setup, this object will be bound bi-directionally to $scope.timeOptions, meaning changes to $scope.timeOptions will reflect in the parent scope's timeRange property, and vice versa.

To implement this change in your directive, you can use:

element.pickatime(scope.timeOptions);

Additonal Information:

In the final example you mention, stating that timeOptions is undefined in the directive. This is due to the need for the HTML to include:

<input type="text" placeholder="Start Time" id="timestart" pick-a-time time-options="timeRange" data-ng-model="itemtimestart" class="form-control" autocomplete="off">

The only modification being timeOptions -> time-options

This adheres to Angular's convention for mapping attributes to scope properties.

Further Clarification:

Your scenario does not necessitate two-way binding. To avoid creating two $watches, consider utilizing & instead of =. The revised version of your directory could look like this:

appDirectives.directive('pickATime', function() { 
    return {
        // Attribute restricted
        restrict: 'A',
        // Manages DOM listeners and updates
        link: function(scope, element, attrs) {
            element.pickatime(scope.options());
        },
        scope: {
            options: '&pickATime'
        },
        templateUrl: '../Templates/timeoptions.html'
    };
});

Usage Example:

Correcting the dot notation issue:

In your controller, ensure you employ dot notation for itemtimestart:

.controller('xxx', function($scope){
    $scope.parameters = {
    }
}

<input ng-if="timeRange" type="text" placeholder="Start Time" id="timestart" pick-a-time="timeRange" data-ng-model="parameters.itemtimestart" class="form-control" autocomplete="off">

$scope.paramters.itemtimestart should now display the correct time.

You can simplify this further by employing the "controller as" syntax.

Explore this Plunk

Answer №2

In case the options are already present in the timeRange and will remain constant, there is no action required: they should be included in scope.timeOptions (both in your link and controller).

However, if the options can change at any moment and you wish to update the component accordingly, you must monitor for these changes:

scope.$watch('timeOptions', function(newOptions) {
  // handle the newOptions here
});

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

Creating a Halo (external outline) for a circular sector in THREE.JS

I'm working on adding a halo (external black outline) to certain shapes in three.js. While I was able to achieve this easily with rectangles and circles, I am facing challenges with circular sectors (not full circles). Here is my current attempt: It ...

Changing HTML elements dynamically within an ng-repeat using AngularJS directives

I have devised an angular directive where I execute an ng-repeat. The fundamental purpose of this directive is to interchange itself with a distinct directive that depends on a value forwarded into the original directive: <content-type-directive type=" ...

Activate the angular function

In the controller below, there is a function that should be triggered when the link is clicked: <a id="1" href="" name="xxx" ng-click="searchall(id)">sample link</a> ng.controller('SearchResultController', ['$scope', &apos ...

ID could not be retrieved from the checkbox

I am facing an issue with my HTML checkboxes. The ids are generated from an angular ng-repeat, but when I try to collect the id for use, it always returns as undefined. $("input:checkbox.time-check-input").each(function () { var ruleUnformatted = ""; ...

AngularJS smart-table / Single row selection

I'm trying to create selectable table rows in smart-table. Using st-select-row="row" and st-select-mode="single" However, I want a selected row to remain selected until the next row is clicked. Currently, when I click on links that open in a new w ...

String creation from HTMLDivElement

Is it possible to create a string from a JavaScript HTMLElement Object? Here's an example: var day = document.createElement("div"); day.className = "day"; day.textContent = "Random Text"; If we have created the day HTMLDivElement Object, can we make ...

Calculating the mean value from a JSON array

I'm having trouble calculating the average from my variable output. I keep getting NaN or zero as a result. Here is my initial output: console.log(data) 0: {nodeId: "53", SNR: "[38.2, 38, 37.9, 37.8, 37.6]", timestamp: "2019-09-05 00:00:17"} Next, ...

Executing a javascript file in a Java environment (Android)

Struggling with logging into a website from an android app? Look no further. In order to successfully submit the POST request with the necessary hashed values, you might need to delve into the website's javascript file. But what if tracing through it ...

Navigating through async functions in an Express.js router

Encountered a lint error indicating that Promises cannot be returned in places where a void is expected. Both functions [validateJWT, getUser] are async functions. Any suggestions on how to resolve this issue without compromising the linter guidelines by u ...

Exploring the CSS scale transformation alongside the Javascript offsetHeight attribute

After combining offsetHeight with scale transformation, I experienced a strange result. Below is my simple HTML code: <body> <div id="id01"> Some Text </div> <div id="id02" style="transform-origin: left top; transf ...

Passing props from pages to components in NextJS: A guide

My nextjs-application has a unique folder structure: components -- layouts --- header.tsx --- index.tsx pages -- index.tsx -- [slug].tsx In the [slug].tsx file, I utilize graphql to fetch data and set the props accordingly: export default ...

Executing a route function in node.js without specifying a form action

When working with node.js and express.js applications, a form action is typically used to call a route function. This is done by specifying the route in the form element like so: <form action="/home"> .... </form> Once the form is submitted, ...

Enter an URL and click the submission button

I'm currently working on a bookmarklet that can grab the URL of the page the user is on, insert that URL into a text field on a specific form, and then automatically submit the form. Here is the code I have so far. It successfully captures the curren ...

Performing a Node.js PATCH request that includes the If-Match header

I have a question that has been puzzling me for some time now. While working with Node.js and creating a PATCH request, I want to set the if-match header to *. Is the code snippet below the correct way to do it? Will this actually work? headers: { &a ...

Transform a javascript object with class attributes into a simple object while keeping the methods

I am seeking a way to convert an instance of a class into a plain object, while retaining both methods and inherited properties. Here is an example scenario: class Human { height: number; weight: number; constructor() { this.height = 1 ...

Change the color of the navbar when scrolling using bootstrap and jquery

Using Bootstrap to design a navigation bar, I have two main goals: I want the navbar to change color when the page is scrolled down by 20%, and then revert back to its original color when scrolling back to the top. When the collapse featu ...

Tips for integrating Vue code into the <code> tag within Vue applications

I am venturing into creating my first npm package and am currently working on the package's demo. I want to showcase an example of how to use the component. However, when I include the component usage within the pre and code tags as shown below: I e ...

split() method cannot be used on date

When working with a string that contains a date in the format 'DD-MM-YYYY' and wanting to change it to 'DD/MM/YYY', it is common practice to use the split method for formatting. The split method successfully separates the string and fo ...

Javascript Guide: Fetching Data from MySQL Database

I need assistance with a PHP-coded web page dedicated to service requests. There are two tables housing all available services and their corresponding prices. When a user selects different services, I aim to retrieve the prices for each selected service a ...

Are you utilizing Google Chrome extensions for importing and exporting JSON files?

Currently, I am in the process of developing a Google Chrome extension and I have a question regarding its capabilities. Is it possible for the extension to generate JSON files for users to download (export) as well as implementing a button that allows use ...