Tips for generating dynamic datepickers using AngularJS

When using my AngularJS application, I display a modal window for editing an event and adding/removing event dates (utilizing Bootstrap datepicker and timepicker).

The event already has some fixed dates, which is not an issue since I have them created and assigned to the ng-model of the datepicker & timepicker.

However, the problem arises when a user clicks the add button to dynamically add new event dates, as I do not have a date variable to assign to the ng-model of the datepicker.

To address this issue, here's what I do:

  1. Within the

    .controller('ModalEditEventP4ctrl',..
    , I handle the modal window (edit event). Here, I have an empty object that I use to add new event dates to the directive addNewDate. $scope.datesObj = {}

  2. The "add new eventdate" button is a directive where I pass a dates array object from the controller. Inside the directive, I create new date objects, push them into the array, and then assign them to the HTML template:

    .directive('addNewDate', function($compile){
      return {
        restrict: 'AE',
        scope: {
            onClick: '&',
            dyndatesObj: '='
        },
        link: function (scope, element, attrs) {
            element.bind('click', function () {                    
            /*1. here I create a new date object and push it into the array */
                scope.dyndatesObj.push({dynDateStart:new Date(),dynDateEnd:new Date(),dtStatus:'1'});
    
               /*2. get the last item */
                var items = $(".row.basicDates").length-1;
    
                /*3. compile another directive 'newDateBlock'*/
                /* and pass it into the DOM*/
                /* the directive is compiled but the datepickers are empty*/
                $('.row.basicDates:eq('+items+')').append($compile("<new-date-block />")(scope));
                scope.$apply();
            });
        }
      }
     })
    
  3. The directive newDateBlock contains the DOM elements which are then compiled through the above directive:

       .directive('newDateBlock', function(){
            return {
                restrict: 'AE',
                scope: {
                    onClick: '&',
                    myDate:'='
                },
                templateUrl: 'assets/modules/part4/templates/addNewDate.tpl.html',
                link: function (scope, element, attrs) {
                    element.bind('click', function () {
                        console.log('inside directive');
                    });
                }
            }
        });
    
  4. The template file addNewDate.tpl.html (not shown entirely). Everything works fine, except for the datepickers. Even though I assign ng-model= datesObj[datesObj.length-1][dynDateStart], they appear empty:

    <div class="row" >   
    <div class="col-md-6">
       <div class="row">
        <div class="col-md-4" style="padding-left: 0;">
            <label>Start Date</label>
            <label>Start Time</label>
        </div>
        <div class="col-md-8" style="padding-left: 0;">
            <p class="input-group">
                <input type="text" class="form-control" style="width:100px"
                       datepicker-popup="{{format}}"
                     /*ng-model does not seem to work*/
                       ng-model="datesObj[datesObj.length-1][dynDateStart]"
                       is-open=""
                       datepicker-options="dateOptions"
                       ng-required="true"
                       close-text="Close"/>
          <span class="input-group-btn" style="float:left">
           <button type="button" class="btn btn-default" ng-click="">
               <i class="glyphicon glyphicon-calendar"></i>
           </button>
          </span>
            </p>
            <timepicker ng-model="" ng-change="changed()" hour-step="1" minute-step="10" show-meridian="false"></timepicker>
        </div>
    </div>
    

https://i.sstatic.net/101fh.png It appears that the value within the ng-model is not being compiled. I'm unsure of the exact cause of the problem. Any assistance would be greatly appreciated.

To be more specific, I'm seeing an error in the browser that states:

TypeError: Cannot read property 'initDate' of undefined
    at link (http://.../bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js:8:23435)
    at http://.../bower_components/angular/angular.min.js:70:141
    at $ (http://.../bower_components/angular/angular.min.js:70:197)
    at B (http://.../bower_components/angular/angular.min.js:59:255)
    at g (http://.../bower_components/angular/angular.min.js:51:335)
    at g (http://.../bower_components/angular/angular.min.js:51:352)
    at g (http:/.../bower_components/angular/angular.min.js:51:352)
    at g (http://.../bower_components/angular/angular.min.js:51:352)
    at g (http://.../bower_components/angular/angular.min.js:51:352)
    at g (http://.../bower_components/angular/angular.min.js:51:352) <input type="text" class="form-control ng-pristine ng-untouched ng-valid ng-isolate-scope" style="width:100px" datepicker-popup="{{format}}" ng-model="datesObj[0].dynDateStart" is-open="" datepicker-options="dateOptions" ng-required="true" close-text="Close">

Answer №1

After spending countless hours and conducting numerous tests, I decided to abandon the directives option and instead implement functions inside the controller to make it work. Each time I add a new date using ng-repeat, I essentially refresh the entire DOM by compiling the entire HTML template. Surprisingly, keeping the HTML template intact yielded perfect results.

Here's what I did:

1. I created the addNewDate() function inside my controller:

$scope.addNewDate = function(){
       //I insert the new item inside my events.eventDates object rather than another array object as before
        $scope.eventmodal.eventDates.push({eventStartDate:new Date(),eventEndDate:new Date(),dateStatus:'1'});
            $templateRequest('/assets/modules/part4/templates/addNewDate.tpl.html').then(function(html){

            // Convert the html to an actual DOM node
            var template = angular.element(html);

            // Clear the previous block of dates completely (not append) and add the new ones
            $('.basicDatesBlock').html(template);

            // Finally compile the template and display it
            $compile(template)($scope);
        });
    };

2. In my addNewDate.tpl.html, I use ng-repeat to display all the eventDates (both old and new) like this:

<div class="row basicDates" ng-repeat="eventdate in eventmodal.eventDates track by $index" ng-show="eventdate.dateStatus == 1">
<!-- start date -->
<div class="col-md-6">
    <div class="row">
        <div class="col-md-4" style="padding-left: 0;">
            <label>Start Date*</label>
            <label>Start Time</label>
        </div>
        <div class="col-md-8" style="padding-left: 0;">
            <p class="input-group">
                <input type="text" class="form-control" style="width:100px"
                       datepicker-popup="{{format}}"
                       ng-model="eventdate.eventStartDate"
                       is-open="openIndex[$index]"
                       datepicker-options="dateOptions"
                       ng-required="true"
                       close-text="Close"/>
          <span class="input-group-btn" style="float:left">
           <button type="button" class="btn btn-default" ng-click="openme($index)">
               <i class="glyphicon glyphicon-calendar"></i>
           </button>
          </span>
            </p>
            <timepicker ng-model="eventdate.eventStartDate" ng-change="changed()" hour-step="1" minute-step="10" show-meridian="false"></timepicker>
        </div>
    </div>
</div>
<!-- end date -->
<div class="col-md-6">
    <div class="row">
        <div class="col-md-5" style="width:31.6%;padding-right:0;">
            <label>End Date*</label>
            <label>End Time</label>
        </div>
        <div class="col-md-7">
            <p class="input-group">
                <input type="text" class="form-control" style="width:100px"
                       datepicker-popup="{{format}}"
                       ng-model="eventdate.eventEndDate"
                       is-open="openIndex[$index]"
                       datepicker-options="dateOptions"
                       ng-required="true"
                       close-text="Close"/>
                    <span class="input-group-btn" style="float:left">
                       <button type="button" class="btn btn-default" ng-click="openme($index)">
                           <i class="glyphicon glyphicon-calendar"></i>
                       </button>
                    </span>
            </p>
            <!-- Show the '+' button only for the first row-->
            <div style="float:right" ng-show="$index==0">
                <div class="plusCircle" style="margin-top:15px">
                    <div class="plusSymbol" ng-click="addNewBasicDate()">+</div>
                </div>
            </div>
            <!-- Show the 'X' button only for 2nd row and greater-->
            <div style="float:right" ng-show="$index>0">
                <div class="plusCircle" style="margin-top:15px">
                    <div class="plusSymbol">x</div>
                </div>
            </div>

            <timepicker ng-model="eventdate.eventEndDate" ng-change="changed()" hour-step="1" minute-step="10" show-meridian="false"></timepicker>
        </div>
    </div>
</div>

https://i.sstatic.net/G5Lkb.png That's the gist of it. I hope this explanation helps others facing similar challenges.

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

A guide on including a clear button in a CustomDatePicker control for .NET MAUI

I recently started diving into the world of .NET MAUI technology, only to discover that the DatePicker control lacks support for null/empty values. To address this issue, I took matters into my own hands and created a custom control using bindable prope ...

Raycasting in three.js - mouse pointer and highlighting not precisely aligned with intersected mesh

My current setup involves using a raycaster to highlight a row of cubes arranged in a grid format. The highlighting works fine, but I'm encountering issues with the cursor turning into a pointer precisely over the cubes in the row. Moreover, the highl ...

What is the best way to reference a dynamic ID in JavaScript when clicking for an action on a different

Here is my HTML code snippet: <table> <tr> <td> @Html.DropDownList("Statues", (SelectList)ViewBag.UserType, string.Empty, new { @class = "NewIDCn",@id = "name1" }) </td> <td> ...

How can I format an array of objects for sorting in javascript?

Trying to implement a sortable list on my view has been challenging. Each row entry is stored as an object in an array, causing issues with string values disrupting the sorting process. This code utilizes Angularjs for implementation. Experimenting with ...

Introduce a pause using the raycaster function

When my raycaster intersects an object for 2 seconds, I want to update the object's texture. I attempted to use the clock function, but I am unsure of how to properly implement it. var clock = new THREE.Clock(); clock.autoStart = true; var inters ...

What is the best way to streamline this using Javascript or jQuery?

Looking for a way to simplify the code for 4 vertical sliding panels? Check out the following script: $(".sliding-panels").click(function() { var n = $(this).attr("number"); var panels = $(".panel"); panels.not(".panel" + n).removeClass("pa ...

Prevent any future dates from being entered

My Thoughts: <input type="text" class="datepicker" placeholder="DD/MM/YYYY" id="datepicker" ng-model="datepicker" name="datepicker" style="width:100%" tabindex="4" required/>` Controller: `$('#datepicker').datepicker({ format: &a ...

Hiding icons in a jquery datatable's table

I am currently developing an inline editing feature, and I would like to display a green checkmark in a column cell to indicate that the record has been updated. However, I need to hide it initially. This is how it looks at the moment: https://i.sstatic. ...

Angular's slide animation effect seems to be malfunctioning and not behaving as anticipated

Just getting started with web development and I'm attempting to create a sliding page in Angular using ng-view. However, I'm running into an issue where when page two enters, it displays below page one until page one is available. You can view th ...

No information available at the moment

When the data is not present, it displays as "display none"... However, I want it to show "no data found" This is the current code if (a.innerHTML.toUpperCase().indexOf(filter) > -1) { li[i].style.display = ""; } else { li[i].styl ...

How to easily incorporate views into a popup using AngularJS

Is there a more efficient way to present views in a popup modal? In my app, I have the main dashboard where users can add or edit items. I want this to be done through a form in a popup modal for a better user experience. I'm aware that jquery can h ...

What is the process for placing API routes within the new app directory of Next.js?

If you have a test API located at: pages\api\accounts\login.js, and are currently exploring the new app folder, which is still in its experimental phase in Next.js (as of today). Are you wondering if it's feasible to transfer your logi ...

What is the best method to assign the value of a useState variable to a specific field in an array of objects for inserting data in

**I have a billing form that includes product details for the admin to fill out. One field, labeled "BillID", should automatically populate with a default value of 'Bill ID + 1' through a variable. **Below is the code: const [BillIdFetch, setB ...

Collecting all Material-UI components into a single document

Currently, I am engaged in a Meteor project that utilizes Material UI and ReactJS. I wish to streamline the process by creating a single file that imports all necessary Material UI components for my project. This way, instead of adding individual exports ...

Extracting the content within HTML tags using regular expressions

There is a specific string structure that needs to be processed: <div class="myClass"> Some Text. </div> <div class="otherClass"> Some Text. </div> The task at hand involves parsing the div with myClass and replacing certa ...

Is it possible to use v-if in conjunction with a style tag to specify a different source file? Alternatively, is there a more efficient method I

I attempted the example provided below, but unfortunately, it did not function as expected. The reason behind my endeavor is that adding numerous modifiers (--tuned) to achieve the desired outcome seemed impractical. Therefore, I decided to try and link ...

An unresolved $httpBackend in Angular's unit testing environment without a defined response

I'm currently facing some difficulties with my first test, so I would appreciate your understanding. The purpose of this test is to evaluate a function that performs an HTTP post request: $scope.formData= 'client=' + $scope.client_selected ...

Trouble with incorporating numbers into Titanium

I have a query about adding a decimal number to a latitude value obtained using forwardGeocoder. Here's the code snippet I am referring to: Ti.Geolocation.forwardGeocoder(textField.value, function(e) { var a = e.latitude; var ...

Prevent clicking here

I'm attempting to only prevent the click event on the current item with a certain class. $(document).on('click', '.item', function() { $(".item").removeClass('is-expanded'); $(this).addClass('is-expanded'); ...

Understanding the Difference Between WARN and ERR in npm Peer Dependency Resolution

I encountered a puzzling situation where two projects faced the same issue, yet npm resolved them differently: https://github.com/Sairyss/domain-driven-hexagon npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! W ...