Manual trigger of show / hide in angularstrap datepicker - angularjs

I want to use a button to show and hide the datepicker.
http://mgcrea.github.io/angular-strap/##datepickers
there are no documentations on how to do this
var app = angular.module('mgcrea.ngStrapDocs', ['ngAnimate', 'ngSanitize',
'mgcrea.ngStrap']);
app.controller('MainCtrl', function($scope) {
});
'use strict';
angular.module('mgcrea.ngStrapDocs')
.config(function($datepickerProvider) {
angular.extend($datepickerProvider.defaults, {
dateFormat: 'dd/MM/yyyy',
startWeek: 1,trigger:manual
});
})
.controller('DatepickerDemoCtrl', function($scope, $http,$datepicker) {
//ng-click
$scope.datepickerpop = function() {
$datepicker.show();
//$datepicker._show();
};
});

This is now much easier with v2.0.4 of ngStrap Datepicker. For more details, see this Github comment. Here's a working plunk to demonstrate the datepicker as both a manually-triggered dropdown, and as a manually-triggered inline element.
<bs-datepicker ng-model="myDatepicker.date" data-bs-show="myDatepicker.show"></bs-datepicker>
In your controller:
$scope.myDatepicker = {
date: null,
show: false
};
You'll also need to override the CSS:
bs-datepicker[bs-show] .datepicker.dropdown-menu,
bs-datepicker[bs-show] + .datepicker.dropdown-menu,
bs-datepicker[data-bs-show] .datepicker.dropdown-menu,
bs-datepicker[data-bs-show] + .datepicker.dropdown-menu {
position: relative;
top: 0 !important;
left: 0 !important;
}
To always show the datepicker, just change the attribute to data-bs-show="true".
If you add the attribute data-container="self", the datepicker will be placed inside the <bs-datepicker> element, which might be useful depending on your needs.

Related

Unable to render the calendar properly for FullCalendar AngularJS Directive

I am new to AngularJS and have to incorporate an Admin LTE full calendar feature in my webapp. I found an Angular directive for the Arshaw FullCalendar JQuery plugin. The link to the directive is here: http://angular-ui.github.io/ui-calendar/
Although I am able to display the calendar, I am not able to get the previous, today and next feature working for the calendar. This help to toggle between the months of the calendar. I know this feature is inside the uiConfig but I am not able to understand why this feature doesn't get rendered.
Below is my code. I have included all the files necessary for the plugin but did not show in index.html.
index.html
<div class="col-xs-12" resize>
<h1>Calendar Page</h1>
<div class="calendar" ng-model="testevents" config="uiConfig.calendar" ui-calendar="{{uiConfig.calendar}}"></div>
calendarController.js
app.controller("calendarController", ["$scope", "displayCalendar", "dialogs", "$filter", function ($scope, displayCalendar, dialogs, $filter) {
$scope.$parent.pageTitle = "Displays Reporting Period Start and End Dates";
/* config object */
$scope.uiConfig = {
calendar: {
height: 450,
editable: true,
header: {
left: 'title',
center: '',
right: 'today prev,next'
},
eventClick: $scope.alertOnEventClick,
eventDrop: $scope.alertOnDrop,
eventResize: $scope.alertOnResize,
eventRender: $scope.eventRender
}
};
$scope.form = {};
$scope.testevents = {
events: [
{
title: 'event1',
start: '2015-12-12'
},
{
title: 'event2',
start: '2015-12-11'
}
// etc...
],
color: 'yellow', // an option!
textcolor: 'black' // an option!
};
}]);
UPDATE:
looking at the demo code on their github page
<div class="calendar" ng-model="eventSources" calendar="myCalendar1" ui-calendar="uiConfig.calendar"></div>
I think you would need to change yours to:
<div class="calendar" ng-model="testevents" calendar="myCalendar1" ui-calendar="uiConfig.calendar"></div>
here is the .html page for their demo
https://github.com/angular-ui/ui-calendar/blob/master/demo/index.html
Have you also added the ui-calendar component to the app initialisation?
'var myAppModule = angular.module('myApp', []);'
inside the [] normally you have to inject a third party component so it can be seen by the rest of your controllers.
Ok.. So after hours and hours of debugging, I figured out what the issue was.
I included fullcalendar.print.css also which was throwing off the styling for fullcalendar.css.
So an advice peeps, if the buttons are not getting rendered properly u might need to consider checking the CSS and remove fullcalendar.print.css.

code highlighting inside textAngular wysiwyg

I have articles, that contain inner programming code.
I used angular-highlightjs for hilight code in frontend, such as:
<div hljs>
<!-- put your codes here -->
</div>
It works fine!
Now I include textAngular for CREATE/UPDATE articles in admin panel, but it erases my "hljs" directive from input articles.
What should I do to fix it? or suggest me angular wysiwyg with code highlight support.
UPD:
Thanks for advice,
this code work fine:
.config(function($provide){
$provide.decorator('taOptions', ['taRegisterTool', '$delegate', '$compile', '$rootScope', function(taRegisterTool, taOptions, $compile, $rootScope){
taRegisterTool('hljs', {
iconclass: "glyphicon glyphicon-eye-open",
tooltiptext: "code highlighting",
action: function() {
var selectedText = window.getSelection();
var hljsTag = '<div hljs>'+ selectedText +'</div>';
var scope = $rootScope.$new();
var element = $compile(hljsTag)(scope);
return this.$editor().wrapSelection('insertHTML', element.html(), true);
}
});
taOptions.toolbar[1].push('hljs');
return taOptions;
}]);
});
You can create your own toolbar button in textAngular for that like this:
module.config(function($provide){
$provide.decorator('taOptions', ['taRegisterTool', '$delegate', function(taRegisterTool, taOptions){
// $delegate is the taOptions we are decorating
// register the tool with textAngular
taRegisterTool('colourRed', {
iconclass: "fa fa-square red",
action: function(){
this.$editor().wrapSelection('forecolor', 'red');
}
});
// add the button to the default toolbar definition
taOptions.toolbar[1].push('colourRed');
return taOptions;
}]);
});
This button will make your selected content in textAngular editor red.
Go to https://github.com/fraywing/textAngular/wiki/Customising-The-Toolbar for more info

Increase width of column in ui.grid

I have inserted some dummy object in Grid,The data displays in the grid found some issues. Here is My code:
html:
<div class="gridStyle" ui-grid="gridOptions"></div>
js:
$scope.myData = [{
JobId: '196',
siteType: 'abc',
Title: 'Happy womans day',
Message: 'hello',
devicetype: 'A',
jobDuration: '819',
totalMsgs: '2016',
msgsDelivered: 'Msg not found In the whole Body',
msgsFailed: '789',
jobCreatedDate: '11-03-2015',
jobCreatedBy: 'abc#abc.com'
}];
$scope.gridOptions = {
data: 'myData'
};
css :
.ui-grid-header-cell .ui-grid-cell-contents {
height: 48px;
white-space: normal;
-ms-text-overflow: clip;
-o-text-overflow: clip;
text-overflow: clip;
overflow: visible;
}
Data displays in the grid but only upto some fixed width. Unable to wrap the long text,
for eg:Msg not found In the whole Body, Displays as Msg not foun...........
How can I increase width of each and every column?
I am not able to wrap the long text lines into 2-3 lines, the whole text displays in one line only
The above css works only for headers
OK, a few things.
Firstly, to set the column width you need to use column definitions, then you can set a width in pixels or percentage on each. Refer http://ui-grid.info/docs/#/tutorial/201_editable as an example that has column widths.
Secondly, there is the ability to add tooltips, which are one way to show longer cells that don't fit in the space available. Refer http://ui-grid.info/docs/#/tutorial/117_tooltips
Thirdly, you can make the rows taller and therefore have space to wrap content within them. Be aware that all rows must be the same height, so you can't make only the rows that need it taller.
gridOptions.rowHeight = 50;
You'll also need to set the white-space attribute on the div so that it wraps, which you can do by setting a class in the cellTemplate, and then adding a style to the css.
A plunker as an example: http://plnkr.co/edit/kyhRm08ZtIKYspDqgyRa?p=preview
Set the Dependency for the javascript:
angular.module('app', [
'ngTouch',
'ui.grid',
'ui.grid.autoResize',
'ui.grid.resizeColumns'
])
for ui-grid 3.0, I am using this directive:
.directive('setOuterHeight',['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element) {
$timeout(function(){
// Get the Parent Divider.
var parentContainer = element.parent()[0];
console.log(parentContainer.offsetHeight);
// Padding of ui-grid-cell-contents is 5px.
// TODO: Better way to get padding height?
var topBottomPadding = 10;
//Get the wrapped contents rowHeight.
var rowHeight = topBottomPadding + parentContainer.offsetHeight;
var gridRowHeight = scope.grid.options.rowHeight;
// Get current rowHeight
if (!gridRowHeight ||
(gridRowHeight && gridRowHeight < rowHeight)) {
// This will OVERRIDE the existing rowHeight.
scope.grid.options.rowHeight = rowHeight;
}
},0);
}
};
}])
Under the controller:
.controller('MainCtrl',
['$scope', '$q', '$timeout', 'uiGridConstants',
function ($scope, $q, $timeout, uiGridConstants) {
$scope.gridOptions = {
enableVerticalScrollbar: uiGridConstants.scrollbars.NEVER,
enableHorizontalScrollbar: uiGridConstants.scrollbars.NEVER,
columnDefs: [
{name: 'firstName', width: '*'},
{name: 'lastName', width: '*'},
{
name: 'company', width: '*',
cellTooltip: function (row) {
return row.entity.company;
},
cellTemplate: '<div class="ui-grid-cell-contents wrap" title="TOOLTIP"><div><span class="label" set-row-height>{{row.entity.company}} </span></div><div>'
},
{name: 'employed', width: '*'}
],
enableColumnResize: true,
rowHeight: 10,
};
}]);
*Note the set-row-height directive for cellTemplate.
For CSS, you will have to put the white-space as normal:
.wrap {
white-space: normal;
}
.wrap .label {
display: inline-block;
}
Lastly, the HTML to change the Grid Height:
<div id="grid1" ui-grid="gridOptions" class="grid" ng-style="{height: (gridOptions.data.length*gridOptions.rowHeight)+32+'px'}" ui-grid-resize-columns ui-grid-auto-resize></div>
Plunker example is here:
http://plnkr.co/edit/OwgEfru0QyFaU1XJFezv?p=preview

How do I create an AngularJS UI bootstrap popover with HTML content?

I want to create a bootstrap popover with a pre tag containing a prettified JSON object. The naive implementation,
<span popover='<pre>{[ some_obj | json:" " ]}</pre>'
popover-trigger='mouseenter'>
escapes the content before inserting it into the popup. What's the best way of specifying a popover body with html content?
UPDATE:
As can been seen in this, you should now be able to do this without overriding the default template.
ORIGINAL:
As of angular 1.2+ ng-bind-html-unsafe has been removed. You should be using the $sce service Reference.
Here is a filter for creating trusted HTML.
MyApp.filter('unsafe', ['$sce', function ($sce) {
return function (val) {
return $sce.trustAsHtml(val);
};
}]);
Here is the overwritten Angular Bootstrap 0.11.2 template making use of this filter
// update popover template for binding unsafe html
angular.module("template/popover/popover.html", []).run(["$templateCache", function ($templateCache) {
$templateCache.put("template/popover/popover.html",
"<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
" <div class=\"arrow\"></div>\n" +
"\n" +
" <div class=\"popover-inner\">\n" +
" <h3 class=\"popover-title\" ng-bind-html=\"title | unsafe\" ng-show=\"title\"></h3>\n" +
" <div class=\"popover-content\"ng-bind-html=\"content | unsafe\"></div>\n" +
" </div>\n" +
"</div>\n" +
"");
}]);
EDIT: Here is a Plunker implementation.
EDIT 2: As this answer keeps getting hits, I'll keep it updated as best I can. As a reference Here is the template from the angular-ui bootstrap repo. If this changes, the override template will require matching updates and the addition of the ng-bind-html=\"title | unsafe\" and ng-bind-html=\"content | unsafe\" attributes to continue working.
For updated conversation check the issue here.
Use the popover-template directive
If you are using a version of angular-ui equal or above 0.13.0, your best option is to use the popover-template directive. Here is how to use it:
<button popover-template="'popover.html'">My HTML popover</button>
<script type="text/ng-template" id="popover.html">
<div>
Popover content
</div>
</script>
NB: Do not forget the quotes around the template name in popover-template="'popover.html'".
See demo plunker
As a side note, it is possible to externalize the popover template in a dedicated html file, instead of declaring it in a <script type="text/ng-template> element as above.
See second demo plunker
I have posted a solution on the github project: https://github.com/angular-ui/bootstrap/issues/520
I you want to add this functionality to your project, here is a patch.
Add those directives:
angular.module("XXX")
.directive("popoverHtmlUnsafePopup", function () {
return {
restrict: "EA",
replace: true,
scope: { title: "#", content: "#", placement: "#", animation: "&", isOpen: "&" },
templateUrl: "template/popover/popover-html-unsafe-popup.html"
};
})
.directive("popoverHtmlUnsafe", [ "$tooltip", function ($tooltip) {
return $tooltip("popoverHtmlUnsafe", "popover", "click");
}]);
And add the template:
<div class="popover {{placement}}" ng-class="{ in: isOpen(), fade: animation() }">
<div class="arrow"></div>
<div class="popover-inner">
<h3 class="popover-title" ng-bind="title" ng-show="title"></h3>
<div class="popover-content" bind-html-unsafe="content"></div>
</div>
</div>
Usage: <button popover-placement="top" popover-html-unsafe="On the <b>Top!</b>" class="btn btn-default">Top</button>
View it on plunkr: http://plnkr.co/edit/VhYAD04ETQsJ2dY3Uum3?p=preview
You need to alter the default popover template to specify you want to allow Html content.
Look the popover-content div, it now has its binding done to the content property allowing unsafe html:
angular.module("template/popover/popover.html", []).run(["$templateCache", function ($templateCache) {
$templateCache.put("template/popover/popover.html",
"<div class='popover {{placement}}' ng-class='{ in: isOpen(), fade: animation() }'>" +
"<div class='arrow'></div><div class='popover-inner'>" +
"<h3 class='popover-title' ng-bind='title' ng-show='title'></h3>" +
"<div class='popover-content' ng-bind-html-unsafe='content'></div>" +
"<button class='btn btn-cancel' ng-click='manualHide()'>Cancel</button>" +
"<button class='btn btn-apply' ng-click='manualHide()'>Apply</button></div></div>");
}]);
For all your conventional Bootstrap popover needs you could utilize the following angular directive. It removes clutter from the HTML template and is very easy to use.
You can configure popover's title, content, placement, fade in/out delay, trigger event and whether content should be treated as html. It also prevents content overflow & clipping.
Related plunker with all teh codes here http://plnkr.co/edit/MOqhJi
Screencap
Usage
<!-- HTML -->
<div ng-model="popup.content" popup="popup.options">Some element</div>
/* JavaScript */
this.popup = {
content: 'Popup content here',
options: {
title: null,
placement: 'right',
delay: { show: 800, hide: 100 }
}
};
JavaScript
/**
* Popup, a Bootstrap popover wrapper.
*
* Usage:
* <div ng-model="model" popup="options"></div>
*
* Remarks:
* To prevent content overflow and clipping, use CSS
* .popover { word-wrap: break-word; }
* Popup without title and content will not be shown.
*
* #param {String} ngModel popup content
* #param {Object} options popup options
* #param {String} options.title title
* #param {Boolean} options.html content should be treated as html markup
* #param {String} options.placement placement (top, bottom, left or right)
* #param {String} options.trigger trigger event, default is hover
* #param {Object} options.delay milliseconds or { show:<ms>, hide:<ms> }
*/
app.directive('popup', function() {
return {
restrict: 'A',
require: 'ngModel',
scope: {
ngModel: '=',
options: '=popup'
},
link: function(scope, element) {
scope.$watch('ngModel', function(val) {
element.attr('data-content', val);
});
var options = scope.options || {} ;
var title = options.title || null;
var placement = options.placement || 'right';
var html = options.html || false;
var delay = options.delay ? angular.toJson(options.delay) : null;
var trigger = options.trigger || 'hover';
element.attr('title', title);
element.attr('data-placement', placement);
element.attr('data-html', html);
element.attr('data-delay', delay);
element.popover({ trigger: trigger });
}
};
});
See https://github.com/jbruni/bootstrap-bower-jbruni, which allow to use a popover-template
The following CSS styling seems to have done what I wanted in my specific case:
.popover-content {
white-space: pre;
font-family: monospace;
}
The general question still remains open.
Here is a fiddle of my solution that:
Is accessible (you can use tab keys to activate/deactivate).
Allows a user to hover the popover and for the popover to remain open.
Allows multiple popovers on the page, but only a single popover to be activated at any given time.
Doesn't rely on any third party, though the bootstrap popover styles have been borrowed.
The way this works is that we instantiate however many popovers we will have on the page in a popover array (see the TODO in the comments on how to wire this up).
Then anytime a user tabs into or hovers into an element that should trigger a popover we activate that specific popover in the popover array. When the user is no longer hovering the element we set a timeout for that specific popover in the array. If that timeout has elapsed it does a quick check to see if the user has re-hovered or re-focused (via tabbing) the element. If so then we keep the popover alive. If not we hide the popover.
For the CSS I did not want to rely on using bootstrap so I borrowed the styles directly from bootstrap. If you try to use bootstrap's popover styles you may run into some weird behavior where bootstrap is running it's own scripts on our custom popover which we do not want.
HTML:
<section>
<a href="#"
ng-mouseover="showPopover(i)"
ng-mouseleave="hidePopover(i)"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">
I trigger a popover - {{i}}
</a>
<popover popover-show="popover[i].popoverTracker">
<div class="arrow"></div>
<div class="custom-popover-content"
ng-mouseover="showPopover(i)"
ng-mouseleave="hidePopover(i)"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">
<a href="#"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">You can tab into me, I'm accessible!</a>
<br/>
<a href="#"
ng-focus="showPopover(i)"
ng-blur="hidePopover(i)">You can tab into me, I'm accessible!</a>
</div>
</popover>
</section>
Angular Controller and Directive:
angular.module('controllers', []);
angular.module('directives', []);
angular.module('myApp', ['ngAnimate', 'controllers', 'directives']);
angular.module('controllers')
.controller('MainCtrl', function ($scope, $timeout) {
$scope.popover = [];
(function init() {
// TODO: Make this dynamic so that we can pass it a value and it will generate the right amount
// Initializing the array of popovers on startup
createPopoverTrackers(20);
})();
// Creating an array of popovers equal to the number of popovers on the page
function createPopoverTrackers(count) {
for(var i = 0; i < count; i++) {
$scope.popover.push({
popoverTracker: false,
popoverKeepAlive: false,
timer: null
})
}
}
// A user has focused on an element that has an associated popover
$scope.queueOpenPopover = function(index) {
// Show our specified tracker
$scope.popover[index].popoverTracker = true;
// Hide the rest
Object.keys($scope.popover)
.filter(function(trackerIndex) {
return trackerIndex != index
})
.forEach(function(trackerIndex) {
$scope.popover[trackerIndex].popoverTracker = false;
$scope.popover[trackerIndex].popoverKeepAlive = false;
const timer = $scope.popover[trackerIndex].timer;
if(timer) {
$timeout.cancel(timer);
$scope.popover[trackerIndex].timer = null;
}
})
};
// Queuing up the demise of the popover
$scope.queueKillPopover = function(index) {
$scope.popover[index].timer = $timeout(function() {
if (!$scope.popover[index].popoverKeepAlive) {
// Popover or the popover trigger were not hovered within the time limit, kill it!
$scope.popover[index].popoverTracker = false;
}
}, 700);
};
// When a user focuses into the actual popover itself or it's trigger, we need to keep it alive
$scope.showPopover = function(index) {
$scope.popover[index].popoverKeepAlive = true;
$scope.queueOpenPopover(index);
};
// The user has removed focus from the popover or it's trigger, set this to false so the timer knows to kill it
$scope.hidePopover = function(index) {
$scope.popover[index].popoverKeepAlive = false;
$scope.queueKillPopover(index);
};
});
angular.module('directives')
.directive('popover', function () {
return {
restrict: 'E',
replace: true,
transclude: true,
scope: {
'popoverShow': '='
},
template: '<div class="custom-popover bottom" ng-show="popoverShow" ng-transclude></div>'
};
});
CSS borrowed from bootstrap:
.custom-popover {
position: absolute;
z-index: 1010;
max-width: 276px;
padding: 1px;
text-align: left;
white-space: normal;
background-color: #fff;
border: 1px solid rgba(0,0,0,0.2);
border-radius: 6px;
box-shadow: 0 5px 10px rgba(0,0,0,0.2);
background-clip: padding-box;
}
.custom-popover .arrow,
.custom-popover .arrow:after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.custom-popover .arrow {
border-width: 11px;
}
.custom-popover .arrow:after {
border-width: 10px;
content: "";
}
.custom-popover.bottom {
margin-top: 10px;
}
.custom-popover.bottom .arrow {
top: -11px;
left: 50%;
margin-left: -11px;
border-bottom-color: rgba(0, 0, 0, 0.25);
border-top-width: 0;
}
.custom-popover.bottom .arrow:after {
top: 1px;
margin-left: -10px;
border-bottom-color: #ffffff;
border-top-width: 0;
content: " ";
}
.custom-popover-content {
padding: 9px 14px;
}

How to validate dynamic form fields in angular directive?

I would like to create form with fields created in directive. Data binding of data working correctly but validation doesn't work.
this is html:
<body ng-controller="MainCtrl">
<h1>form</h1>
<form name="form">
<div ng-repeat="conf in config">
<div field data="data" conf="conf"></div>
</div>
</form>
<pre>{{data|json}}</pre>
</body>
controller and field directive:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.data = {name: '', age: ''}
$scope.config = [
{field: 'name', required:true},
{field: 'age'}
];
});
app.directive('field', function ($compile) {
return {
scope: {
data: '=',
conf: '='
},
link: function linkFn(scope, element, attrs) {
// field container
var row = angular.element('<div></div>');
// label
row.append(scope.conf.field + ': ');
// field input
var field = angular.element('<input type="text" />');
field.attr('name', scope.conf.field);
field.attr('ng-model', 'data.' + scope.conf.field);
if (scope.conf.required) {
field.attr('required', 'required');
}
row.append(field);
// validation
if (scope.conf.required) {
var required = angular.element('<span>required</span>');
required.attr('ng-show',
'form.' + scope.conf.field + '.$error.required');
row.append(required);
}
$compile(row)(scope);
element.append(row);
}
}
});
problem is that validation for field name doesn't work and validation text required is never shown. May be form in ng-show is unknown in directive. But I don't know how to pass form into field directive. Can you help me how to fix it? Thanks.
here is live code: http://plnkr.co/edit/j0xc7iV1Sqid2VK6rMDF?p=preview
Todo:
before:
$compile(row)(scope);
element.append(row);
after:
element.append(row);
$compile(row)(scope);
p/s in 'planker' for facilities add css:
.ng-invalid {
border: 1px solid red;
}
You'll need to use ng-form directive and push the dynamic field directly into form object.
This thread can help you out:
https://github.com/angular/angular.js/issues/1404
Here is a plunker forked from yours to fix you're issue:
http://plnkr.co/edit/qoMOPRoSnyIdMiZnbnDF?p=preview
To summarize, I added a watch that will toggle the error message instead of using the ng-show directive. Things can get hairy when you attempt to dynamically add a directive within a directive link. For a simple use case as this, it is quicker to add your own watch.
You may also look at this directive which is preconfigured to handle many use cases for validation as well as allow you to create custom validations easily https://github.com/nelsonomuto/angular-ui-form-validation
var toggleRequiredErrorMessage = function (invalid) {
if(invalid === true) {
addRequiredErrorMessage();
} else {
removeRequiredErrorMessage();
}
};
scope.$watch( watchIfRequired, toggleRequiredErrorMessage );

Resources