Bootstrap timepicker selects only the first timepicker element - javascript

I have a form where a user can add dynamic bootstrap timepicker fields.
I'm using Bootstrap timepicker (https://github.com/eternicode/bootstrap-datepicker) for timepicker input fields that will be dynamically generated
The problem is, when clicking on any datepicker element (except the first one), all the changes happen to the first one only.
Here is the JSFIDDLE
The HTML part of my code is:
<div class="row multi-field-wrapper">
<div class="multi-fields">
<div class="multi-field">
<div class="form-group col-xs-12 col-sm-4">
<div class="input-group">
<input type="text" name="ticket-price" maxlength="5" class="form-control" placeholder="FREE" >
<span class="input-group-btn">
<button class="btn btn-default add-field" type="button">+</button>
</span>
<span class="input-group-btn">
<button class="btn btn-default remove-field" type="button">-</button>
</span>
</div>
</div>
<div class="row">
<div class="form-group col-xs-6 col-sm-3">
<label>Start Date</label>
<input type="text" name="tstart-date" class="form-control tstart-date-picker" placeholder="">
</div>
</div>
</div>
</div>
</div>

The problem is that you clone DOM elements with event handlers attached by jQuery. It causes troubles when you try to select date in new input, because events bound by datepicker somehow mixed up with original on from the first input.
The fix is pretty simple: clone without true argument, and also use delegated click event for adding new rows. The rest doesn't change:
$(this).on('click', '.add-field', function (e) {
$('.multi-field:first-child', $wrapper).clone().appendTo($wrapper);
$('.multi-field:last-child').find('input[name="tstart-date"]').val('');
$('.multi-field:last .tstart-date-picker').datepicker({
autoclose: true,
format: 'dd-M-yyyy',
todayHighlight: true,
});
});
Demo: http://jsfiddle.net/z2j6u8ro/2/

The datepicker must be assigned to each element specifically. Try this:
$(".add-field", $(this)).click(function(e) {
(CODE TO ADD NEW FIELD HERE)
$(.tstart-date-picker).each(function(){
$(this).datepicker("destroy");
$(this).datepicker({
(DATEPICKER OPTIONS HERE)
});
});
}

Related

JQuery DateTimepicker allow user text input

How do I use a jQuery Datetimepicker with a user textbox input?
$(document).on('click', '#txtUserDateTime', function (evt) {
$('#txtUserDateTime').datetimepicker({
format: 'm/d/Y H:i',
step: 5,
minDate: 0
});
});
In the above image I can set Date and Time and the textbox is readonly. Sometimes I wanted to change only the time as some text like for example: "w/c" etc. but the datetimepicker textbox is not allowing me to hold the value after click outside of the event.
The Datetimepicker("#txtUserDateTime") textbox doesn't allow the user input. Can we achieve this?
And below is my cshtml code:
<div class="col-sm-3">
<div class="input-group date">
<span class="csts-date-time-picker" style="width: 100%;">
<input asp-for="NeedDate" type="text" id="txtCraneDateTime" class="form-control" tabindex="0">
</span>
<span asp-validation-for="NeedDate" class="text-danger"></span>
</div>
</div>

Need to open the datepicker popup on click of the calendar icon instead of clicking on the input field

my below datepicker code is like below. Its working fine. But the datepicker popup opens when i click on the input field. But want that to be open once i click on the calendar icon. Please suggest me a way to achieve that.
<div class="col-sm-6 col-md-6 col-lg-6 padleft">
<div class="form-group">
<label for="exampleSelect1">Start Date
</label>
<div class="input-group" style="width:75%">
<div class="input-group-btn">
<input type="text"
class="form-control date"
id="dateFrom"
placeholder="From"
ng-click="model.dateFrom=true"
datepicker-popup="{{model.format}}"
ng-model="model.defect.startDate"
is-open="model.dateFrom"
datepicker-options="dateOptions"
date-disabled="model.disabled(date, mode)"
ng-required="true"
close-text="Close" my-date>
<span class="btn btn-default " ng-click="model.dateFrom=true"><i class="glyphicon glyphicon-calendar"></i> </span>
</div>
</div>
</div>
</div>
In My controller :
self.format = 'MM-dd-yyyy';
self.open = function($event) {
$event.preventDefault();
$event.stopPropagation();
self.opened = {};
self.opened[$event.target.id] = true;
// log this to check if its setting the log
console.log(self.opened);
};
Angular : 1.6
Using 'ui.bootstrap.datetimepicker',
and 'ui.bootstrap
You'll need to add ng-click="model.dateFrom=true" as an attribute to the <i> element containing your calendar icon, not its parent span.
I would actually recommend writing a separate function for toggling the datepicker on and off. Something like
$scope.toggleDatePicker = function() {
$scope.model.dateFrom = !$scope.model.dateFrom;
};
and then calling that from your html: ng-click="toggleDatePicker()"

Adding fields dynamically inside an element which is also added dynamically Jquery

I have a set of fields which can be duplicated. Now within those fields there are also particular fields which are duplicated.
This is an example of my markup
<div class="item_1">
<button type="button" class="fluid-inline btn btn-primary add_items">Add fields</button>
<hr />
<div class="col-sm-4 m-b-10px">
<label><h5>OCCUPATION: </h5></label>
<input name=b_occ[] type="text" class="form-control" required=required>
</div>
<div class="col-sm-4 m-b-10px">
<label><h5>WORK ADDRESS: </h5></label>
<input name=b_work_add[] type="text" class="form-control" required=required>
</div>
<div class="item_victim_relation">
<div class="col-sm-4 m-b-10px">
<label><h5>VICTIM: </h5></label>
<select class="form-control" name="victim_name[]" required=required>
<option value="victim_id"><h5>Victim</h5></option>
</select>
</div>
<div class="col-sm-4 m-b-10px">
<label><h5>RELATION TO VICTIM: </h5></label>
<input name=b_relation[] type="text" class="form-control" required=required>
</div>
<div class="col-sm-4 m-b-10px">
<h5 class="text-info">(IF SUSPECT HAS RELATION TO MULTIPLE VICTIMS) </h5>
<button type="button" class="dashed-button add_victim_b">Add</button>
</div>
</div>
</div>
JS
var removeButtonV = "<button type=button class='dashed-button remove_item_v'>Remove</button>";
var removeButton = "<button type=button class='btn btn-primary m-b-10px remove_items'>Remove</button>";
$('.add_victim_b').click(function() {
$('div.item_victim_relation:last').
after($('div.item_victim_relation:first').clone());
$('.add_victim_b:last').remove();
$('.text-info:last').text("(REMOVE THESE FIELDS)");
$(removeButtonV).insertAfter(('.text-info:last'));
});
$(document).on('click', '.remove_item_v', function(){
$(this).closest('div.item_victim_relation').remove();
});
$('.add_items').click(function() {
$('div.item_1:last').after($('div.item_1:first').clone());
$('div.item_1:last').append(removeButton);
$('hr.item_b_separator:last').removeClass('hidden');
});
$(document).on('click', '.remove_items', function(){
$(this).closest('div.item_1').remove();
});
This piece of code duplicates victim and relation to victim fields. It works fine when item_1 is not yet duplicated, but when it is, those two fields are appended on the last instance of the fields inside the last instance of item_1 too. What I want to happen is for these two fields to be appended after their last instances on the item_1 where they belong.
I think my way of traversal is wrong. I've tried several methods but I can't seem to get it work.
Here is a demonstration of the problem:
DEMO
Here is a sample of what I want (each has their own class names and item_1 cannot be duplicated but it would not work if item_1 would be cloned)
jQuery is only aware of the elements in the page at the time it runs, so new elements added to the DOM dynamically are unrecognized by jQuery. To combat the problem use event delegation, bubbling events from newly added items up to a point in the DOM which was there when jQuery ran on page load. Many people use document as the place to catch the bubbled event, but it isn't necessary to go all the way up the DOM tree. Ideally you should delegate to the nearest parent existing at the time of page load.
$(document).on('click', 'button.ok', function(e){...
Using the .on() function should solve your issue.
I managed to solve it by changing my traversal methods and just assigning the fields to be added in a variable.
I have changed the handler of add_victim_b to this
var victimFields = '<div class="item_victim_relation"><div class="col-sm-4 m-b-10px"><label><h5>VICTIM: </h5></label><select class="form-control" name="victim_name[]" required=required><option value="victim_id"><h5>Victim</h5></option></select></div><div class="col-sm-4 m-b-10px"><label><h5>RELATION TO VICTIM: </h5></label><input name=b_relation[] type="text" class="form-control" required=required></div><div class="col-sm-4 m-b-10px"><h5 class="text-info">(REMOVE FIELDS) </h5><button type="button" class="dashed-button remove_victim_b"><i class="fa fa-minus" aria-hidden=true></i></button></div><div class="clearfix"></div></div>';
$(document).on('click', '.add_victim_b', function(){
var item_b_index = $(this).closest('.item_b').index('.item_b');
$(victimFields).insertAfter($('div.item_b').eq(item_b_index).find('.item_victim_relation:last'));
});
It now works perfectly as I wanted it. You may view it here:
DEMO

Bootstrap datetimepicker for the id of div

I have the date picker working when I set the id for the input tag like the following:
<div class="col-sm-4" id="datepicker">
<input type="text" class="form-control" id="inputDate" placeholder="Date">
<span class="glyphicon glyphicon-calendar form-control-feedback" aria-hidden="true"></span>
</div>
<script type="text/javascript">
$(function () {
$('#inputDate').datetimepicker();
});
</script>
I just wonder why its not working if I used the div instead of the input tag ( the datepicker id), as I saw some examples online using the div instead of the input.
It wont work if you don't set class input-group on <div>
Check it here https://jsfiddle.net/a9729dc9/
.datetimepicker(); init the input that will use the datepicker feature, that why we should call it on the concerned input field.
If you want to reference to the input through the div you could use it as :
$('#datepicker input').datetimepicker();
//Or also
$('#datepicker #inputDate').datetimepicker();
In bootstrap you have to add class .input-group to the parent (container) div so bootstrap could detect input-group-addon and init the picker, e.g :
<div class="input-group" id="datepicker">
<input type="text" class="form-control">
<div class="input-group-addon">
<span class="glyphicon glyphicon-th"></span>
</div>
</div>
Hope this helps.

how to create dynamically datepickers in angularjs

on my angularjs application i show a modal window to edit an event and add/remove event dates(i use bootstrap datepicker and timepicker).
the event has some fixed dates, i dont have problem with that because i have them created first and i use them on ng-model (of the datepicker & timepicker).
the problem is when the user press the add button to add new event dates dynamically, i dont have date variable to assign to the ng-model of the datepicker .
what i do to achieve that:
inside .controller('ModalEditEventP4ctrl',.. i manipulate the modal window(edit event).here i have a an empty object that i use it to add new eventdates into the directive addNewDate.
$scope.datesObj = {}
the add new eventdate button is a directive, where i pass a dates array object from the controller. Inside the directive i create new dates objects and push them on the array, so as to assign it into 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 new date object and push it on 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 it is compiled but the datepickers are empty*/
$('.row.basicDates:eq('+items+')').append($compile("<new-date-block />")(scope));
scope.$apply();
});
}
}
})
the directive newDateBlock that has the DOM elements which i compile it through the ebove directive is this:
.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');
});
}
}
});
the template file addNewDate.tpl.html(i dont show it all). everything works ok , except from the datepickers that ,although i assign them ng-model= datesObj[datesObj.length-1][dynDateStart], they are 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 seems not 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>
it seems that the value inside the ng-model is not compiled , i dont know exactly what is the problem. any help would be appreciated.
to be more specific, i get the error (on the browser) that says:
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">
After many hours and too many tests i quited the directives option and i made it work with functions inside the controller where i $compile the whole html template each time i add new date ,with ng-repeat , like refresh the whole DOM, i just keep the html template because it works perfect.
what i did:
1. inside my controller i created the addNewDate() function:
$scope.addNewDate = function(){
//i push the new item inside my events.eventDates object and not in another array object as previously
$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 completely(not append) the previous block of dates and add the new ones
$('.basicDatesBlock').html(template);
// finally $compile the template and show it.
$compile(template)($scope);
});
};
2. my addNewDate.tpl.html i use the ng-repeat to show all the eventDates (the old + the new ones) 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>
<!-- i 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" add-new-date dyndates-obj = datesObj>+</div>-->
<div class="plusSymbol" ng-click="addNewBasicDate()">+</div>
</div>
</div>
<!-- i 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>
And that's it. i tried to make myself clear , i hope it helps other guys with similar problems.

Categories

Resources