I need to update all my datepickers so they display current day highlighted. I found code custom-class="getDayClass(date, mode)" , but do i really need to copy-paste this to EVERY datepicker directive? Is there a way to set it in config so it affect all datepickers already existing on a page?
I tried uibDatepickerPopupConfig.customClass = function(data){return "class"} but its not working.
thanks
I found solution without modifying source code.
First we need to add new template to $templateCache and then we need to extend datepicker directive scope with new function for returning custom class.
$templateCache.put("uib/template/datepicker/day.html",
"<table role=\"grid\" aria-labelledby=\"{{::uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
" <thead>\n" +
" <tr>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left uib-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-left\"></i><span class=\"sr-only\">previous</span></button></th>\n" +
" <th colspan=\"{{::5 + showWeeks}}\"><button id=\"{{::uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm uib-title\" ng-click=\"toggleMode()\" ng-disabled=\"datepickerMode === maxMode\" tabindex=\"-1\"><strong>{{title}}</strong></button></th>\n" +
" <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right uib-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i aria-hidden=\"true\" class=\"glyphicon glyphicon-chevron-right\"></i><span class=\"sr-only\">next</span></button></th>\n" +
" </tr>\n" +
" <tr>\n" +
" <th ng-if=\"showWeeks\" class=\"text-center\"></th>\n" +
" <th ng-repeat=\"label in ::labels track by $index\" class=\"text-center\"><small aria-label=\"{{::label.full}}\">{{::label.abbr}}</small></th>\n" +
" </tr>\n" +
" </thead>\n" +
" <tbody>\n" +
" <tr class=\"uib-weeks\" ng-repeat=\"row in rows track by $index\" role=\"row\">\n" +
" <td ng-if=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
" <td ng-repeat=\"dt in row\" class=\"uib-day text-center\" role=\"gridcell\"\n" +
" id=\"{{::dt.uid}}\"\n" +
" ng-class=\"::dt.customClass\">\n" +
" <button type=\"button\" class=\"btn btn-default btn-sm\"\n" +
" ng-class=\"highlightCurrentDate(dt)\"\n" +
" uib-is-class=\"\n" +
" 'btn-info' for selectedDt,\n" +
" 'active' for activeDt\n" +
" on dt\"\n" +
" ng-click=\"select(dt.date)\"\n" +
" ng-disabled=\"::dt.disabled\"\n" +
" tabindex=\"-1\"><span ng-class=\"::{'text-muted': dt.secondary, 'text-info': dt.current}\">{{::dt.label}}</span></button>\n" +
" </td>\n" +
" </tr>\n" +
" </tbody>\n" +
"</table>\n" +
"");
You see we addednew line ng-class=\"highlightCurrentDate(dt)\"\n" +
And then we extend datepicker scope as i wrote:
angular.module('ui.bootstrap.datepicker')
.config(function ($provide) {
$provide.decorator('uibDatepickerDirective', function ($delegate, $timeout) {
var directive = $delegate[0];
var link = directive.link;
directive.compile = function () {
return function (scope, element, attrs, ctrls) {
link.apply(this, arguments);
scope.highlightCurrentDate = function (dt) {
if (dt.selected) {
return "";
}
var date = dt.date;
var dayToCheck = new Date(date).setHours(0, 0, 0, 0);
var currentDay = new Date().setHours(0, 0, 0, 0);
if (dayToCheck === currentDay) {
return 'highlight-current-date';
}
}
};
return $delegate;
});
});
Related
I'm using this slightly modified treeview directive (https://github.com/eu81273/angular.treeview, jFiddle Example) in my app. I can get it to save the node that has been selected, but I can't seem to figure out how to display the treeview with a node already selected, if the user edits previously saved form.
Treeview Directive:
angular.module('App').directive('treeModel', ['$compile', function ($compile) {
return {
restrict: 'A',
controller: treeviewController,
link: function (scope, element, attrs) {
//tree id
var treeId = attrs.treeId;
//tree model
var treeModel = attrs.treeModel;
//node id
var nodeId = attrs.nodeId || 'id';
//node label
var nodeLabel = attrs.nodeLabel || 'label';
//children
var nodeChildren = attrs.nodeChildren || 'children';
//tree template
var template =
'<ul>' +
'<li data-ng-repeat="node in ' + treeModel + '">' +
'<i class="collapsed" data-ng-show="node.' + nodeChildren + '.length && node.collapsed" data-ng-click="' + treeId + '.selectNodeHead(node)"></i>' +
'<i class="expanded" data-ng-show="node.' + nodeChildren + '.length && !node.collapsed" data-ng-click="' + treeId + '.selectNodeHead(node)"></i>' +
'<i class="normal" data-ng-hide="node.' + nodeChildren + '.length" data-ng-class="node.selected" data-ng-click="' + treeId + '.selectNodeLabel(node)"></i> ' +
'<span data-ng-hide="node.' + nodeChildren + '.length" class="tree-item" data-ng-class="node.selected" data-ng-click="' + treeId + '.selectNodeLabel(node)">{{node.' + nodeLabel + '}}</span>' +
'<span data-ng-show="node.' + nodeChildren + '.length" class="tree-node" data-ng-class="node.selected" data-ng-click="' + treeId + '.selectNodeLabel(node)">{{node.' + nodeLabel + '}}</span>' +
'<div data-ng-hide="node.collapsed" data-tree-id="' + treeId + '" data-tree-model="node.' + nodeChildren + '" data-node-id=' + nodeId + ' data-node-label=' + nodeLabel + ' data-node-children=' + nodeChildren + '></div>' +
'</li>' +
'</ul>';
//check tree id, tree model
if (treeId && treeModel) {
//root node
if (attrs.angularTreeview) {
//create tree object if not exists
scope[treeId] = scope[treeId] || {};
//if node head clicks,
scope[treeId].selectNodeHead = scope[treeId].selectNodeHead || function (selectedNode) {
//Collapse or Expand
selectedNode.collapsed = !selectedNode.collapsed;
};
// my attempt at pre-loading a selected node
if (scope.savedNode != undefined) {
scope[treeId].currentNode = scope.savedNode;
//scope.savedNode comes from the controller, and looks like this...
/*{
"children": [],
"collapsed": false,
"selected": "selected",
"treeNodeName": "Node name here",
"treeNodeId": "eY40Ik"
}*/
}
//if node label clicks,
scope[treeId].selectNodeLabel = scope[treeId].selectNodeLabel || function (selectedNode) {
// only allow to select nodes that are not expandable
if (!selectedNode.children.length) {
//remove highlight from previous node
if (scope[treeId].currentNode && scope[treeId].currentNode.selected) {
scope[treeId].currentNode.selected = undefined;
}
//toggle currentNode
if (scope[treeId].currentNode == selectedNode) {
scope[treeId].currentNode = {};
selectedNode = {};
scope.currentSelectedNode = {
name: "",
id: ""
};
} else {
scope[treeId].currentNode = selectedNode;
selectedNode.selected = 'selected';
scope.currentSelectedNode = {
name: selectedNode.sourceName,
id: selectedNode.sourceId
}
}
}
};
}
//Rendering template.
element.html('').append($compile(template)(scope));
}
}
};
}]);
HTML:
<div data-angular-treeview="true"
data-tree-id="treeId"
data-tree-model="treeData"
data-node-id="treeNodeId"
data-node-label="treeNodeName"
data-node-children="children">
</div>
Only the selected node is being saved, not the entire tree-model.
How would I load up a tree with a node already selected?
Here is how I am adding fields.
$scope.addEmailField = function () { //Function to add new email field.
if (valid <= 1 && checkToDelete == 0) {
var mailTxtId = 'mail' + valid;
var mailModel = 'Contact_Email' + valid;
var hide = 'hide' + valid;
hide = false;
console.log(mailTxtId);
var emailDiv = angular.element(document.querySelector('#emailDiv'));
var element = $compile('<div id="' + mailTxtId + '" style="margin-left: -60px; width:200px; margin-top:15px"><input id= "' + mailModel + '" type = "text" class="form-control" ng-model="' + mailModel + '" ng-blur="validateEmailDynamic(' + valid + ')">' +
'<input id="' + valid + '" class="form-control" style="margin-left: 206px; width:54px; margin-top:-34px" type="button" value="-" ng-click="deleteField(' + valid + ')"><span ng-show ="' + hide + '" style="color:red">' +
'Invalid email</span></div>')($scope);
emailDiv.append(element);
valid = valid + 1;
}
};
But not getting the value of ng-model.
Store your input box in a directive's template. Then add ng-class that would determine whether it should show or not.
app.directive('inputBox', function(){
template:'<input ng-model="item">'
});
Usage in the html:
<div ng-class="{ input-box : triggerInputBox }"></div>
Controller:
$scope.triggerInputBox = true;
This is just one of many ways to accomplish this. But directives are very useful for dynamically showing templates.
I am using angular data table from below link
http://l-lin.github.io/angular-datatables/archives/#!/bindAngularDirective
I am using the defer rending concept here.
I have 2 button
Active (Show when user status is 1)
Inactive (Show when user status is 0)
As 2 way data binding not working here. I am unable to show Inactive button after clicking on active & viceversa
Below is my code
$scope.setCustomers = function (s, dto, dtc, f, c, h, t) {
s.dtInstance = {};
s.actions = {};
//dtOptions - Makes the ajax request to get the customer records, also builds the buttons to copy,csv,excel..etc
s.dtOptions = dto.fromSource('customers/showCustomers.json')
.withPaginationType('full_numbers')
.withDisplayLength(25)
.withOption('createdRow', createdRow)
.withDOM('<"html5buttons"B>lTfgitp').withDisplayLength(25);
// dtColumns - Builds the columns and renders the rows for each column
s.dtColumns = [
dtc.newColumn('name').withTitle('Name'),
dtc.newColumn('email').withTitle('Email'),
dtc.newColumn('phone').withTitle('Phone'),
dtc.newColumn('status').withTitle('Status')
.renderWith(function (data) {
return "<div style=text-align:center;>" + (data == 1 ? 'Accepted' : data == 2 ? 'Declined' : 'Pending') + "</div>";
}),
dtc.newColumn(null).withTitle('Actions').notSortable()
.renderWith(actionsHtml)
];
function createdRow(row, data, dataIndex) {
c(angular.element(row).contents())(s);
}
function actionsHtml(data, type, full, meta) {
s.actions[data.id] = data;
var actions = '<button ladda="loadingDemo' + data.customer_id + '" class="ladda-button ladda-button-demo btn btn-primary btn-xs" data-style="zoom-in" ng-click="resetPassword(actions[' + data.id + '])" uib-tooltip="Reset Password" tooltip-placement="top"><i class="fa fa-key"></i></button> '
+ '<i class="fa fa-money"></i></button> '
+ '<i class="fa fa-files-o"></i></button> '
+ '<i class="fa fa-eye"></i></button> '
+ '<i class="fa fa-pencil"></i></button> ';
if (data.is_active == 1) {
actions += '<button class="btn btn-success btn-xs" data-is_active="' + data.is_active + '" ng-click="setStatus(actions[' + data.id + '])" tooltip-placement="top" uib-tooltip="Inactive"><i class="fa fa-thumbs-up"></i></button> ';
} else {
actions += '<button class="btn btn-danger btn-xs" data-is_active="' + data.is_active + '" ng-click="setStatus(actions[' + data.id + '])" tooltip-placement="top" uib-tooltip="Active"><i class="fa fa-thumbs-down"></i></button> ';
}
return actions;
}
}
$scope.setCustomers($scope, DTOptionsBuilder, DTColumnBuilder, $filter, $compile, $http, toaster);
Thanks
I want to integrate facebook Widget for getting facebook group's timeline / posts. I have searched & got this https://developers.facebook.com/docs/plugins/page-plugin but this gives user's & page's timeline. I wanted Group's timeline. I didn't found perfect answer on Fb Developer portal & didn't get anything on web.
Any help on this is appreciated.
Thanks in Advance.
After lots of search, no plugin kind of thing i got for this. But yes got one blog in php where the developer made custom widget manually, I modified it with JavaScript & jQuery.
<div style="height: 375px; background: #f6f7f9;">
<div id="fb-root"></div>
<p class="text-center media-body social-link" style="background: white">
<img src="~/Content/Images/Link-Red.png" />
Facebook Group
</p>
<div id="fix-div"></div>
<div id="facebook-group" style="overflow-y: scroll; height: 375px; margin-top: 55px;"></div>
</div>
Facebook JavaScript API as follows-
<script>
var access_token = '<!-- Valid fb access token -->';
var groupId = 'valid facebook group id';
window.fbAsyncInit = function () {
FB.init({
appId: 'valid facebook app id',
cookie: true,
xfbml: true,
version: 'v2.8'
});
FB.api("" + groupId + "?fields=cover,icon,name,privacy",
'get',
{ access_token: access_token },
function (groupResponse) {
if (groupResponse && !groupResponse.error) {
$("#fix-div").html('');
$("#facebook-group").html('');
var fixDivHtml =
"<div style='z-index: 10;position: absolute;border: 1px solid #e9ebee;max-width: 470px;background: white;min-height: 50px;'><div class='media' style='border: 0'><div class='media-left media-middle' style='vertical-align: bottom'><a href='https://www.facebook.com/groups/" + groupResponse.id + "' target='_blank'><img class='media-object' src='/Content/Images/Facebook-group.png' style='min-height: 50px;padding: 5px 10px;width: 64px;'></a></div><div class='media-body media-middle'><a href='https://www.facebook.com/groups/" + groupResponse.id + "' target='_blank'><h4 class='media-heading' style='font-size: 14px;font-weight: bold;'>" + groupResponse.name + "</h4></a></div></div></div>";
$("#fix-div").append(fixDivHtml);
FB.api("/" +
groupId +
"/feed?fields=id,message,link,attachments{media,description},created_time,from,object_id,parent_id&limit=1000",
'get',
{ access_token: access_token },
function (response) {
if (response && !response.error) {
for (var i = 0; i < response.data.length; i++) {
var picture = undefined;
var description = undefined;
var date = formatDate(response.data[i].created_time);
if (response.data[i].attachments !== undefined) {
if (response.data[i].attachments.data.length > 0) {
if (
response.data[i].attachments.data[0].media !==
undefined) {
if (
response.data[i].attachments.data[0].media
.image !==
undefined)
picture = response.data[i].attachments
.data[0].media.image.src;
if (
response.data[i].attachments.data[0].media
.image.description !==
undefined)
description = response.data[i].attachments
.data[0].media.image.description;
} else {
if (
response.data[i].attachments.data[0]
.description !==
undefined)
description = response.data[i].attachments
.data[0].description;
}
}
}
var message = response.data[i].message;
var
append =
"<div class='border'><div class='media'><div class='media-left media-middle'><a href='https://www.facebook.com/" + response.data[i].from.id + "' target='_blank'><img class='media-object' src='http://graph.facebook.com/" + response.data[i].from.id + "/picture?type=square'></a></div><div class='media-body' style='vertical-align: bottom'><a href='https://www.facebook.com/" + response.data[i].from.id + "' target='_blank'><h4 class='media-heading'>" + response.data[i].from.name + ".<br /><small>" + date + "</small></h4></a></div>";
if (message !== undefined) {
if (ValidURL(message) === 1) {
append +=
"<a class='ellipsis' href='" +
message +
"' target='_blank'>" +
message +
"</a>";
} else {
append += "<a class='ellipsis'>" + message + "</a>";
}
}
if (picture !== undefined)
append +=
"<a href='" +
response.data[i].link +
"' target='_blank'><img class='img-responsive' src='" +
picture +
"'/></a>";
if (description !== undefined)
append += "<p>" + description + "</p>";
append += '<hr///>' +
"<div class='btn-group btn-group-justified' role='group' aria-label='Justified button group'>" +
"<a href=" +
response.data[i].link +
" class='btn btn-default' role='button' target='_blank'><i class='fa fa-thumbs-up' aria-hidden='true'></i> Like</a>" +
"<a href=" +
response.data[i].link +
" class='btn btn-default' role='button' target='_blank'><i class='fa fa-comment' aria-hidden='true'></i> Comment</a></div></div></div>";
$("#facebook-group").append(append);
}
}
});
}
});
};
(function () {
var e = document.createElement('script');
e.async = true;
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
document.getElementById('fb-root').appendChild(e);
}());
var formatDate = function (input) {
var d = new Date(Date.parse(input));
input = d.toString();
d = new Date(Date.parse(input.replace(/-/g, "/")));
var month = [
'january', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
'September', 'October', 'November', 'December'
];
var date = d.getDay().toString() +
" " +
month[d.getMonth().toString()] +
", " +
d.getFullYear().toString();
return (date);
};
function ValidURL(str) {
if (
/^(http|https|ftp):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i.test(str))
return 1;
else
return -1;
}
</script>
Here formatDate & ValidURL are helper functions used for some cosmetic operations.
Here is my problem:
I have a button, with I can add dynamically inputs.And specifically add a textarea with div element above it which contains a counter for chars in textarea.The problems is that angular tags are rendering as ordinary html text.
mainController :
var validationApp = angular.module('validationApp', []).config(function ($interpolateProvider) {
$interpolateProvider.startSymbol('<%').endSymbol('%>');
});
validationApp.controller('mainController', function ($scope, $compile) {
var max_fields = 10; //maximum input boxes allowed
var wrapper = $(".activities_wrap"); //Fields wrapper
var add_button = $(".my-add_field_button"); //Add button ID
var x = 0; //initlal text box count
var elements = "<div class=\"char-counter\">Остават Ви <% (100 - projectManagement['project_management[0][activity]'].$viewValue.length) > 0 ? (100 - projectManagement['project_management[0][activity]'].$viewValue.length) : 0 %> символа" + +"</div>" +
"<div><h3>Дейност #" + x + "</h3>" +
"<textarea ng-model=\"project_management.activity" + x + "\" ng-maxlength=\"100\" name=\"project_management[" + x + "][activity]\" placeholder=\"Дейност\"></textarea>" +
"<input class=\"from\" type=\"text\" name=\"project_management[" + x + "][from]\" placeholder=\"Начална дата\">" +
"<input class=\"to\" type=\"text\" name=\"project_management[" + x + "][to]\" placeholder=\"Крайна дата\">" +
"<input type=\"text\" name=\"project_management[" + x + "][place]\" placeholder=\"Място\">" +
"<input type=\"text\" name=\"project_management[" + x + "][responsible_for_activity]\" placeholder=\"Отговорен за дейността\">" +
"<input type=\"text\" name=\"project_management[" + x + "][count_participants]\" placeholder=\"Брой включени участници\">" +
"<textarea type=\"text\" name=\"project_management[" + x + "][indicators_for_measure_of_activity]\" placeholder=\"Индикатори за измерване на дейността\"></textarea>" +
"<br>Премахни</div>";
$(add_button).click(function (e) { //on add input button click
e.preventDefault();
if (x < max_fields) { //max input box allowed
x++; //text box increment
$(wrapper).append(elements); //add input box
$('.from, .to').datepicker({
dateFormat: 'dd-mm-yy',
dayNames: ["Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"],
dayNamesMin: ["Нд", "По", "Вт", "Ср", "Чт", "Пт", "Сб"],
monthNames: ["Януари", "Февруари", "Март", "Април",
"Май", "Юни", "Юли", "Август", "Септември",
"Октомври", "Ноември", "Декември"]
}).val();
$compile(elements)($scope);
}
});
$(wrapper).on("click", ".remove_field", function (e) { //user click on remove text
e.preventDefault();
$(this).parent('div').remove();
x--;
})
});
HTML :
<fieldset ng-form="projectManagement">
<div class="activities_wrap">
<button class="action-button my-add_field_button">Добави дейност</button>
</div>
<input type="button" name="previous" class="previous action-button" value="Назад"/>
<input type="button" name="next" class="next action-button" ng-disabled="projectManagement.$invalid" value="Напред"/>
<script>
$('.from, .to').datepicker({
dateFormat: 'dd-mm-yy',
dayNames: ["Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота", "Неделя"],
dayNamesMin: ["Нд", "По", "Вт", "Ср", "Чт", "Пт", "Сб"],
monthNames: ["Януари", "Февруари", "Март", "Април",
"Май", "Юни", "Юли", "Август", "Септември",
"Октомври", "Ноември", "Декември"]
}).val();
</script>
This is not exactly an answer, but a simple example that will, hopefully, help you understand the "angular thinking".
AngularJS is different that JQuery in a way that your view is completely dependent of your data structure. Changes in your data will reflect in view changes, in the same way that, changes in the view may reflect in an update to your data. This is all done by a mechanism called Data-Binding. I'm not that good at explaining so a made a simple example. Besides, you should really study about Data-Binding, ViewModel pattern and Angular in general. You will see that, thankfully, you will not need Jquery for much.
So, to achieve what you want, you need to hold an array of objects in your controller, and push new items to it with the click of a button. This array will store objects with the properties you want to store, like ID, NAME, etc. Each of those properties will be binded to a input, so that they can be edited.
Here is an example of what I'm trying to explain.
https://jsfiddle.net/relferreira/42zrn2t2/1/
JS
angular.module('app', []);
angular.module('app')
.controller('MainController', mainController);
mainController.$inject = ['$scope'];
function mainController($scope){
var vm = this;
vm.itemsList = [];
vm.addItem = addItem;
function addItem(){
vm.itemsList.push({});
}
}
HTML
<div data-ng-app="app">
<div data-ng-controller="MainController as mainVm">
<button data-ng-click="mainVm.addItem()">ADD</button>
<table>
<thead>
<th>ID</th>
<th>Name</th>
</thead>
<tbody>
<tr data-ng-repeat="item in mainVm.itemsList">
<td><input type="number" data-ng-model="item.id"></td>
<td><input type="text" data-ng-model="item.name"></td>
</tr>
</tbody>
</table>
{{mainVm.itemsList}}
</div>
</div>
Take a look at this question for more information
"Thinking in AngularJS" if I have a jQuery background?