You need a control to enter minutes and seconds in a project, but after investigating some open source projects, you don't find the right controls. There is a similar control timepicker in the angular Bootstrap UI, but it has no depth to the precision of minutes and seconds.
So decide to refer to its source code and implement it yourself.
The final effect is as follows:
The first is the definition of the directive:
App.directive (' Minutesecondpicker ', function () {return
{
restrict: ' EA ',
require: [' Minutesecondpicker ', ' ^ngmodel '],
controller: ' Minutesecondpickercontroller ',
replace:true,
scope: {
Validity: ' = '
},
templateurl: ' partials/directives/minutesecondpicker.html ',
link:function (scope, Element, Attrs, ctrls) {
var Minutesecondpickerctrl = ctrls[0],
Ngmodelctrl = ctrls[1];
if (Ngmodelctrl) {
minutesecondpickerctrl.init (Ngmodelctrl, element.find (' input '));}};
In the above link function, Ctrls is an array: ctrls[0] is the controller instance defined on this directive, Ctrls[1 is Ngmodelctrl, the Ng-model instance corresponding to controller. This order is actually defined by require: [' minutesecondpicker ', '? ^ngmodel '].
note that the first dependency is the name of the directive itself, and the corresponding instance of the Controller declaration in the directive is passed in. The second dependency is a bit odd: "^ngmodel", which means that even if the dependency is not found, do not throw an exception, that is, the dependency is an optional option. The meaning of ^ is to find the controller of the parent element.
Then, define some of the default settings that are used in the directive, implemented through constant directive:
App.constant (' Minutesecondpickerconfig ', {
minutestep:1,
secondstep:1,
readonlyinput:false,
Mousewheel:true
});
followed by the directive corresponding controller, its declaration is as follows:
App.controller (' Minutesecondpickercontroller ', [' $scope ', ' $attrs ', ' $parse ', ' Minutesecondpickerconfig
', function ($scope, $attrs, $parse, minutesecondpickerconfig) {
...
In the directive link function, the Init method for this controller is invoked:
This.init = function (Ngmodelctrl_, inputs) {
Ngmodelctrl = Ngmodelctrl_;
Ngmodelctrl. $render = This.render;
var Minutesinputel = inputs.eq (0),
Secondsinputel = Inputs.eq (1);
var mousewheel = angular.isdefined ($attrs. MouseWheel)?
$scope. $parent. $eval ($attrs. MouseWheel): Minutesecondpickerconfig.mousewheel;
if (mousewheel) {
this.setupmousewheelevents (Minutesinputel, Secondsinputel);
}
$scope. Readonlyinput = angular.isdefined ($attrs. readonlyinput)?
$scope. $parent. $eval ($attrs. Readonlyinput): Minutesecondpickerconfig.readonlyinput;
This.setupinputevents (Minutesinputel, Secondsinputel);
};
The second parameter accepted by the Init method is inputs, which is passed in the link function: Element.find (' input '). So the first input box is used to enter a minute, and the second input box is used to enter a second.
Then, check to see if the MouseWheel property is overwritten, and if not overridden, use the default MouseWheel set in constant, and make the relevant settings as follows:
Respond on MouseWheel spin
this.setupmousewheelevents = function (Minutesinputel, Secondsinputel) {
var Isscrollingup = function (e) {
if (e.originalevent) {
e = e.originalevent;
}
Pick correct delta variable depending on event
var delta = (e.wheeldata)? E.wheeldata:-e.deltay;
Return (E.detail | | Delta > 0);
Minutesinputel.bind (' MouseWheel wheel ', function (e) {
$scope. $apply ((Isscrollingup (e))? $ Scope.incrementminutes (): $scope. Decrementminutes ());
E.preventdefault ();
});
Secondsinputel.bind (' MouseWheel wheel ', function (e) {
$scope. $apply ((Isscrollingup (e))? $ Scope.incrementseconds (): $scope. Decrementseconds ());
E.preventdefault ();
});
The Init method finally makes some settings for the inputs itself:
Respond on direct Input this.setupinputevents = function (Minutesinputel, Secondsinputel) {if ($scope. readonlyinput)
{$scope. updateminutes = Angular.noop;
$scope. updateseconds = Angular.noop;
Return
var invalidate = function (Invalidminutes, invalidseconds) {Ngmodelctrl. $setViewValue (NULL);
Ngmodelctrl. $setValidity (' time ', false);
$scope. Validity = false;
if (angular.isdefined (invalidminutes)) {$scope. invalidminutes = invalidminutes;
} if (angular.isdefined (invalidseconds)) {$scope. invalidseconds = invalidseconds;
}
};
$scope. updateminutes = function () {var minutes = getminutesfromtemplate ();
if (angular.isdefined (minutes)) {selected.minutes = minutes;
Refresh (' m ');
else {invalidate (true);
}
}; Minutesinputel.bind (' Blur ', function (e) {if (! $scope. invalidminutes && $scope. Minutes <) {$scope. $apply
(function () {$scope. minutes = Pad ($scope. minutes);
});
}
}); $scope. updateseconds = function () {var seconds = Getsecondsfromtemplate ();
if (angular.isdefined (seconds)) {selected.seconds = seconds;
Refresh (' s ');
else {invalidate (undefined, true);
}
}; Secondsinputel.bind (' Blur ', function (e) {if (! $scope. Invalidseconds && $scope. Seconds <) {$scope. $apply
(function () {$scope. seconds = Pad ($scope. seconds);
});
}
});
};
In this method, a invalidate function is declared to set the illegal entry, exposing a validity = false attribute in scope to give the page an opportunity to react appropriately.
If a user uses a variable to represent minutestep or secondstep, then a corresponding watchers is also required:
var minutestep = minutesecondpickerconfig.minutestep;
if ($attrs. minutestep) {
$scope. Parent. $watch ($parse ($attrs. Minutestep), function (value) {
Minutestep = parseint (value, ten);}
);
var secondstep = minutesecondpickerconfig.secondstep;
if ($attrs. secondstep) {
$scope. Parent. $watch ($parse ($attrs. Secondstep), function (value) {
Secondstep = parseint (value, ten);}
);
The complete Directive implementation code is as follows:
var app = Angular.module ("Minutesecondpickerdemo");
App.directive (' Minutesecondpicker ', function () {return {restrict: ' EA ', require: [' minutesecondpicker ', '? ^ngmodel '], Controller: ' Minutesecondpickercontroller ', replace:true, scope: {validity: ' = '}, Templateurl: ' Partials/direct
Ives/minutesecondpicker.html ', link:function (scope, element, Attrs, ctrls) {var Minutesecondpickerctrl = ctrls[0],
Ngmodelctrl = ctrls[1];
if (Ngmodelctrl) {minutesecondpickerctrl.init (Ngmodelctrl, element.find (' input '));
}
}
};
});
App.constant (' Minutesecondpickerconfig ', {minutestep:1, secondstep:1, Readonlyinput:false, mousewheel:true}); App.controller (' Minutesecondpickercontroller ', [' $scope ', ' $attrs ', ' $parse ', ' minutesecondpickerconfig ', function ( $scope, $attrs, $parse, Minutesecondpickerconfig) {var selected = {minutes:0, seconds:0}, Ngmodelctrl = {$
SetViewValue:angular.noop}; This.init = function (Ngmodelctrl_, inputs) {Ngmodelctrl = Ngmodelctrl_;
Ngmodelctrl. $render = This.render;
var Minutesinputel = inputs.eq (0), Secondsinputel = Inputs.eq (1);
var mousewheel = angular.isdefined ($attrs. MouseWheel)?
$scope. $parent. $eval ($attrs. MouseWheel): Minutesecondpickerconfig.mousewheel;
if (MouseWheel) {this.setupmousewheelevents (Minutesinputel, Secondsinputel);
$scope. Readonlyinput = angular.isdefined ($attrs. readonlyinput)?
$scope. $parent. $eval ($attrs. Readonlyinput): Minutesecondpickerconfig.readonlyinput;
This.setupinputevents (Minutesinputel, Secondsinputel);
};
var minutestep = Minutesecondpickerconfig.minutestep; if ($attrs. minutestep) {$scope. Parent. $watch ($parse ($attrs. Minutestep), function (value) {minutestep = parseint (value
, 10);
});
var secondstep = Minutesecondpickerconfig.secondstep; if ($attrs. secondstep) {$scope. Parent. $watch ($parse ($attrs. Secondstep), function (value) {secondstep = parseint (value
, 10);
}); }//Respond on MouseWheel spin this.setupmousewheelevents = function (Minutesinputel, Secondsinputel) {var isscrollingup = function (e) {if (e.originalevent) {e = e.original
Event; }//Pick correct delta variable depending on event var delta = (e.wheeldata)?
E.wheeldata:-e.deltay;
Return (E.detail | | Delta > 0);
}; Minutesinputel.bind (' MouseWheel wheel ', function (e) {$scope. $apply ((Isscrollingup (e)) $scope. Incrementminutes (): $
Scope.decrementminutes ());
E.preventdefault ();
}); Secondsinputel.bind (' MouseWheel wheel ', function (e) {$scope. $apply ((Isscrollingup (e)) $scope. Incrementseconds (): $
Scope.decrementseconds ());
E.preventdefault ();
});
};
Respond on direct Input this.setupinputevents = function (Minutesinputel, Secondsinputel) {if ($scope. readonlyinput) {
$scope. updateminutes = Angular.noop;
$scope. updateseconds = Angular.noop;
Return
var invalidate = function (Invalidminutes, invalidseconds) {Ngmodelctrl. $setViewValue (NULL);
Ngmodelctrl. $setValidity (' time ', false); $scoPe.validity = false;
if (angular.isdefined (invalidminutes)) {$scope. invalidminutes = invalidminutes;
} if (angular.isdefined (invalidseconds)) {$scope. invalidseconds = invalidseconds;
}
};
$scope. updateminutes = function () {var minutes = getminutesfromtemplate ();
if (angular.isdefined (minutes)) {selected.minutes = minutes;
Refresh (' m ');
else {invalidate (true);
}
}; Minutesinputel.bind (' Blur ', function (e) {if (! $scope. invalidminutes && $scope. Minutes <) {$scope. $apply
(function () {$scope. minutes = Pad ($scope. minutes);
});
}
});
$scope. updateseconds = function () {var seconds = getsecondsfromtemplate ();
if (angular.isdefined (seconds)) {selected.seconds = seconds;
Refresh (' s ');
else {invalidate (undefined, true);
}
}; Secondsinputel.bind (' Blur ', function (e) {if (! $scope. Invalidseconds && $scope. Seconds <) {$scope. $apply
(function () {$scope. seconds = Pad ($scope. seconds);
}); }
});
}; This.render = function () {var time = Ngmodelctrl. $modelValue?
{Minutes:ngmodelctrl. $modelValue. Minutes, Seconds:ngmodelctrl. $modelValue. seconds}: null;
Adjust the time to invalid value at the I/I if (Time.minutes < 0) {time.minutes = 0;
} if (Time.seconds < 0) {time.seconds = 0;
var totalseconds = time.minutes + time.seconds;
Time = {Minutes:Math.floor (totalseconds/60), seconds:totalseconds% 60};
if (time) {selected = time;
Makevalid ();
Updatetemplate ();
}
};
Call internally while the model is valid function refresh (keyboardchange) {makevalid ();
Ngmodelctrl. $setViewValue ({minutes:selected.minutes, seconds:selected.seconds});
Updatetemplate (Keyboardchange);
function Makevalid () {Ngmodelctrl. $setValidity (' time ', true);
$scope. Validity = true;
$scope. Invalidminutes = false;
$scope. Invalidseconds = false; function Updatetemplate (keyboardchange) {var minutes = Selected.minutes, SEconds = Selected.seconds; $scope. minutes = Keyboardchange = = ' m '?
Minutes:pad (minutes); $scope. seconds = Keyboardchange = = = ' s '?
Seconds:pad (seconds); function Pad (value) {return (angular.isdefined (value) && value.tostring (). length < 2)?
' 0 ' + value:value;
function Getminutesfromtemplate () {var minutes = parseint ($scope. minutes, 10); Return (minutes >= 0)?
minutes:undefined;
function Getsecondsfromtemplate () {var seconds = parseint ($scope. seconds, 10);
if (seconds >=) {seconds = 59; return (seconds >= 0)?
seconds:undefined;
$scope. incrementminutes = function () {addseconds (Minutestep * 60);
};
$scope. decrementminutes = function () {addseconds (-minutestep * 60);
};
$scope. incrementseconds = function () {addseconds (secondstep);
};
$scope. decrementseconds = function () {addseconds (-secondstep);
}; function addseconds (seconds) {var newseconds = Selected.minutes * + selected.seconds + SecondS
if (Newseconds < 0) {newseconds = 0;
} selected = {Minutes:Math.floor (newseconds/60), seconds:newseconds% 60};
Refresh (); $scope. previewtime = function (minutes, seconds) {var totalseconds = parseint (minutes, Ten) * + parseint (seconds, 1
0), hh = Pad (Math.floor (totalseconds/3600)), MM = pad (minutes%), SS = pad (seconds);
return hh + ': ' + mm + ': ' + ss;
};
}]);
Corresponding template implementation: &NBSP;
<table> <tbody> <tr class= "Text-center" > <td> <a ng-click= "incrementminutes ()" Class= "BT n Btn-link "> <span class=" Glyphicon glyphicon-chevron-up "></span> </a> </td> <td> ; </td> <td> <a ng-click= "incrementseconds ()" class= "btn btn-link" > <span class= "Glyphico
n glyphicon-chevron-up "></span> </a> </td> <td> </td> </tr> <tr> <TD style= "width:50px class=" Form-group "ng-class=" {' Has-error ': invalidminutes} "> <input type=" text "ng-m Odel= "Minutes" ng-change= "updateminutes ()" class= "Form-control text-center" ng-mousewheel= "Incrementminutes" () " Ng-readonly= "Readonlyinput" maxlength= "3" > </td> <td>:</td> <td style= "width:50px" "class=" f Orm-group "ng-class=" {' Has-error ': invalidseconds} "> <input type=" text "ng-model=" Seconds "ng-change=" Updateseconds () "class=" Form-control text-centeR "ng-mousewheel=" Incrementseconds () "ng-readonly=" Readonlyinput "maxlength=" 2 "> <td> <!--preview column
--> <td> <span class= "label label-primary" ng-show= "validity" > {{previewtime (minutes, seconds)}} </span> </td> </tr> <tr class= "Text-center" > <td> <a ng-click= "decrementminutes () "class=" btn btn-link "> <span class=" Glyphicon glyphicon-chevron-down "></span> </a> </td&
Gt <td> </td> <td> <a ng-click= "decrementseconds ()" class= "btn btn-link" > <span class=
"Glyphicon glyphicon-chevron-down" ></span> </a> </td> <td> </td> </tr>
</tbody> </table>
Test code (that is, the source code of the previous screenshot dialog):
<div class= "Modal-header" >
If you want to further study, you can click here to learn, and then attach 3 wonderful topics:
Bootstrap Learning Course
Bootstrap Practical Course
Bootstrap Plugin Usage Tutorial
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.