Kendo datepicker is dispalying date in long format with time how to avoid it - knockout-2.0

This is code I am using can be seen by clicking the this link
http://jsfiddle.net/fGq5w/1/
On click of the button , I change the date. But the time is also displayed.
How to display one date alone when i click the button.
HTML CODE
<input id="myDatePicker" data-bind="value: currentDate" />
<h2>Current Date is:<strong data-bind="text: currentDate"></strong></h2>
<input type='button' value='change Date' onclick='changeDate();return false;' />
Javascript
var vm = {
currentDate: ko.observable()
};
$(function(){
ko.applyBindings(vm);
$("#myDatePicker").kendoDatePicker();
});
function changeDate()
{
alert('ok');
vm.currentDate(new Date(2014,1,1));
}

This is more of a Kendo question. Just format the date with kendo's date formatting tools:
http://docs.kendoui.com/getting-started/framework/globalization/dateformatting
eg...
vm.currentDate(kendo.toString(new Date(2013,0,1), "MM/dd/yyyy"));

Your Code with additional functionality to pre-fill the date TextBox.
var vm = {
currentDate: ko.observable(kendo.toString(new Date(),'MM/dd/yyyy'))
};
$(function(){
ko.applyBindings(vm);
$("#myDatePicker").kendoDatePicker();
});
enter code here
function changeDate()
{
alert('ok');
vm.currentDate(kendo.toString(new Date(2014,1,1),'MM/dd/yyyy'));
}

In Knockout 3.3.0, you can create an extension to handle the formatting since calling a function manually isn't terribly ideal:
(In the snipper below I'm using moment.js to parse the date, but you could use kendo's date parser - although it doesn't work with certain ISO formatted dates)
ko.extenders.stripTime = function (target) {
var result = ko.pureComputed({
read: target,
write: function (value) {
if (value) {
target(moment(value).format(shell.getDateFormatString()));
}
else {
target(value);
}
}
}).extend({ notify: 'always' });
result(target());
return result;
};
In your client-side viewmodel, apply the extension to your observable:
self.SomeDateProperty = ko.observable().extend({ stripTime: null });
I recommend not using ko.toJS when you try to get a javascript object from your observables when using kendo datepicker - Instead, use ko.mapping (you need to download the JS library separately).
var someJavascriptObject = ko.mapping.toJS(viewModel);

Related

Using Fragment to insert HTML rendered on the back end via dangerouslySetInnerHTML

I used to compile and insert JSX components via
<div key={ ID } dangerouslySetInnerHTML={ { __html: HTML } } />
which wrapped my HTML into a <div>:
<div>my html from the HTML object</div>
Now react > 16.2.0 has support for Fragments and I wonder if I can use that somehow to avoid wrapping my HTML in a <div> each time I get data from the back end.
Running
<Fragment key={ ID } dangerouslySetInnerHTML={ { __html: HTML } } />
will throw a warning
Warning: Invalid prop `dangerouslySetInnerHTML` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.
in React.Fragment
Is this supported yet at all? Is there another way to solve this?
Update
Created an issue in the react repo for it if you want to upvote it.
Short Answer
Not possible:
key is the only attribute that can be passed to Fragment. In the
future, we may add support for additional attributes, such as event
handlers.
https://reactjs.org/docs/fragments.html
You may want to chime in and suggest this as a future addition.
https://github.com/facebook/react/issues
In the Meantime
You may want to consider using an HTML parsing library like:
https://github.com/remarkablemark/html-react-parser
Check out this example to see how it will accomplish your goal:
http://remarkablemark.org/blog/2016/10/07/dangerously-set-innerhtml-alternative/
In Short
You'll be able to do this:
<>
{require('html-react-parser')(
'<em>foo</em>'
)}
</>
Update December 2020
This issue (also mentioned by OP) was closed on Oct 2, 2019. - However, stemming from the original issue, it seems a RawHTML component has entered the RFC process but has not reached production, and has no set timeline for when a working solution may be available.
That being said, I would now like to allude to a solution I currently use to get around this issue.
In my case, dangerouslySetInnerHTML was utilized to render plain HTML for a user to download; it was not ideal to have additional wrapper tags included in the output.
After reading around the web and StackOverflow, it seemed most solutions mentioned using an external library like html-react-parser.
For this use-case, html-react-parser would not suffice because it converts HTML strings to React element(s). Meaning, it would strip all HTML that wasn't standard JSX.
Solution:
The code below is the no library solution I opted to use:
//HTML that will be set using dangerouslySetInnerHTML
const html = `<div>This is a div</div>`
The wrapper div within the RawHtml component is purposely named "unwanteddiv".
//Component that will return our dangerouslySetInnerHTML
//Note that we are using "unwanteddiv" as a wrapper
const RawHtml = () => {
return (
<unwanteddiv key={[]}
dangerouslySetInnerHTML={{
__html: html,
}}
/>
);
};
For the purpose of this example, we will use renderToStaticMarkup.
const staticHtml = ReactDomServer.renderToStaticMarkup(
<RawHtml/>
);
The ParseStaticHtml function is where the magic happens, here you will see why we named the wrapper div "unwanteddiv".
//The ParseStaticHtml function will check the staticHtml
//If the staticHtml type is 'string'
//We will remove "<unwanteddiv/>" leaving us with only the desired output
const ParseStaticHtml = (html) => {
if (typeof html === 'string') {
return html.replace(/<unwanteddiv>/g, '').replace(/<\/unwanteddiv>/g, '');
} else {
return html;
}
};
Now, if we pass the staticHtml through the ParseStaticHtml function you will see the desired output without the additional wrapper div:
console.log(ParseStaticHtml(staticHtml));
Additionally, I have created a codesandbox example that shows this in action.
Notice, the console log will throw a warning: "The tag <unwanteddiv> is unrecognized in this browser..." - However, this is fine because we intentionally gave it a unique name so we can easily differentiate and target the wrapper with our replace method and essentially remove it before output.
Besides, receiving a mild scolding from a code linter is not as bad as adding more dependencies for something that should be more simply implemented.
i found a workaround
by using react's ref
import React, { FC, useEffect, useRef } from 'react'
interface RawHtmlProps {
html: string
}
const RawHtml: FC<RawHtmlProps> = ({ html }) => {
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!ref.current) return
// make a js fragment element
const fragment = document.createDocumentFragment()
// move every child from our div to new fragment
while (ref.current.childNodes[0]) {
fragment.appendChild(ref.current.childNodes[0])
}
// and after all replace the div with fragment
ref.current.replaceWith(fragment)
}, [ref])
return <div ref={ref} dangerouslySetInnerHTML={{ __html: html }}></div>
}
export { RawHtml }
Here's a solution that works for <td> elements only:
type DangerousHtml = {__html:string}
function isHtml(x: any): x is DangerousHtml {
if(!x) return false;
if(typeof x !== 'object') return false;
const keys = Object.keys(x)
if(keys.length !== 1) return false;
return keys[0] === '__html'
}
const DangerousTD = forwardRef<HTMLTableCellElement,Override<React.ComponentPropsWithoutRef<'td'>,{children: ReactNode|DangerousHtml}>>(({children,...props}, ref) => {
if(isHtml(children)) {
return <td dangerouslySetInnerHTML={children} {...props} ref={ref}/>
}
return <td {...props} ref={ref}>{children}</td>
})
With a bit of work you can make this more generic, but that should give the general idea.
Usage:
<DangerousTD>{{__html: "<span>foo</span>"}}</DangerousTD>

Liferay 7 date picker does not trigger onChange

I added this AUI date picker to my JSP:
<aui:input
type="text"
id="myDate"
name="my-date"
value="2017-12-14"
placeholder="yyyy-mm-dd"
onChange="javascript:alert('date changed');"/>
<aui:script>
AUI().use(
'aui-datepicker',
function(A) {
new A.DatePicker(
{
trigger: '#<portlet:namespace/>myDate',
mask: '%Y-%m-%d',
popover: {
zIndex: 1000
}
}
);
}
);
</aui:script>
Problem: Changing the date using the calendar widget that pops up does not display the alert.
If I ignore the widget and change the date manually (using the keyboard), the alert correctly shows up as soon as the input loses focus.
What am I doing wrong?
How to have onChange be called whenever the date is changed, be via mouse or keyboard?
As the guys in the comments mentioned use the js callback definitions. There are a couple of examples in the documentation.
https://alloyui.com/examples/datepicker
If you really want to have the onChange also there, you can trigger the change event from the js callback code.
<button class="btn btn-primary"><i class="icon-calendar icon-white"></i> Select the date</button>
<script>
YUI().use(
'aui-datepicker',
function(Y) {
new Y.DatePicker(
{
trigger: 'button',
popover: {
zIndex: 1
},
on: {
selectionChange: function(event) {
console.log(event.newSelection)
}
}
}
);
}
);
</script>

Avoid to show the keyboard when a selectOneMenu is selected on mobile devices

I need to avoid to show the keyboard when a selectOneMenu is selected on mobile devices
Someone suggests to use h:selectOneMenu in this question:
How do I prevent the keyboard from popping up on a p:selectOneMenu using Primefaces?
But I need to use the p:selectOneMenu component
You can override the SelectOneMenu focusFilter function.
What we have to do is adding one more condition, if it's not a mobile device do the focus otherwise don't do it.
Here's the overridden function, just execute it in the document.ready.
//check if it's a mobile device
mobileDevice = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
PrimeFaces.widget.SelectOneMenu.prototype.focusFilter = function(timeout) {
if(!mobileDevice) {
if(timeout) {
var $this = this;
setTimeout(function() {
$this.focusFilter();
}, timeout);
}
else {
this.filterInput.focus();
}
}
}
Then we check if it's a mobileDevice again, if so we remove the foucsInput this time
if(mobileDevice) {
for (var propertyName in PrimeFaces.widgets) {
if (PrimeFaces.widgets[propertyName] instanceof PrimeFaces.widget.SelectOneMenu) {
PrimeFaces.widgets[propertyName].focusInput.remove();
}
}
}
Note: This has been fixed in PrimeFaces 5.2.
A small working example can be found on github, And an online Demo.
Try these on the id of your selectOneMenu (using jQuery)
$(".mySelect").focus(function() {
$(this).blur();
});
OR
$('body').on("focus", '.mySelect', function(){
$(this).blur();
});
OR other example using the blur attribute (using just javascript):
If the HTML for these fields looked like this:
<input type="text" name="username" id="username">
<input type="password" name="password" id="password">
Then the JavaScript would be:
document.getElementById('username').blur();
document.getElementById('password').blur();
Blur: is an event is sent to an element when it loses focus
These worked for me before.
I hope this helps!
:)

How to put a delay on AngularJS instant search?

I have a performance issue that I can't seem to address. I have an instant search but it's somewhat laggy, since it starts searching on each keyup().
JS:
var App = angular.module('App', []);
App.controller('DisplayController', function($scope, $http) {
$http.get('data.json').then(function(result){
$scope.entries = result.data;
});
});
HTML:
<input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />
<div class="entry" ng-repeat="entry in entries | filter:searchText">
<span>{{entry.content}}</span>
</div>
The JSON data isn't even that large, 300KB only, I think what I need to accomplish is to put a delay of ~1 sec on the search to wait for the user to finish typing, instead of performing the action on each keystroke. AngularJS does this internally, and after reading docs and other topics on here I couldn't find a specific answer.
I would appreciate any pointers on how I can delay the instant search.
UPDATE
Now it's easier than ever (Angular 1.3), just add a debounce option on the model.
<input type="text" ng-model="searchStr" ng-model-options="{debounce: 1000}">
Updated plunker:
http://plnkr.co/edit/4V13gK
Documentation on ngModelOptions:
https://docs.angularjs.org/api/ng/directive/ngModelOptions
Old method:
Here's another method with no dependencies beyond angular itself.
You need set a timeout and compare your current string with the past version, if both are the same then it performs the search.
$scope.$watch('searchStr', function (tmpStr)
{
if (!tmpStr || tmpStr.length == 0)
return 0;
$timeout(function() {
// if searchStr is still the same..
// go ahead and retrieve the data
if (tmpStr === $scope.searchStr)
{
$http.get('//echo.jsontest.com/res/'+ tmpStr).success(function(data) {
// update the textarea
$scope.responseData = data.res;
});
}
}, 1000);
});
and this goes into your view:
<input type="text" data-ng-model="searchStr">
<textarea> {{responseData}} </textarea>
The mandatory plunker:
http://plnkr.co/dAPmwf
(See answer below for a Angular 1.3 solution.)
The issue here is that the search will execute every time the model changes, which is every keyup action on an input.
There would be cleaner ways to do this, but probably the easiest way would be to switch the binding so that you have a $scope property defined inside your Controller on which your filter operates. That way you can control how frequently that $scope variable is updated. Something like this:
JS:
var App = angular.module('App', []);
App.controller('DisplayController', function($scope, $http, $timeout) {
$http.get('data.json').then(function(result){
$scope.entries = result.data;
});
// This is what you will bind the filter to
$scope.filterText = '';
// Instantiate these variables outside the watch
var tempFilterText = '',
filterTextTimeout;
$scope.$watch('searchText', function (val) {
if (filterTextTimeout) $timeout.cancel(filterTextTimeout);
tempFilterText = val;
filterTextTimeout = $timeout(function() {
$scope.filterText = tempFilterText;
}, 250); // delay 250 ms
})
});
HTML:
<input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />
<div class="entry" ng-repeat="entry in entries | filter:filterText">
<span>{{entry.content}}</span>
</div>
In Angular 1.3 I would do this:
HTML:
<input ng-model="msg" ng-model-options="{debounce: 1000}">
Controller:
$scope.$watch('variableName', function(nVal, oVal) {
if (nVal !== oVal) {
myDebouncedFunction();
}
});
Basically you're telling angular to run myDebouncedFunction(), when the the msg scope variable changes. The attribute ng-model-options="{debounce: 1000}" makes sure that msg can only update once a second.
<input type="text"
ng-model ="criteria.searchtext""
ng-model-options="{debounce: {'default': 1000, 'blur': 0}}"
class="form-control"
placeholder="Search" >
Now we can set ng-model-options debounce with time and when blur, model need to be changed immediately otherwise on save it will have older value if delay is not completed.
For those who uses keyup/keydown in the HTML markup.
This doesn't uses watch.
JS
app.controller('SearchCtrl', function ($scope, $http, $timeout) {
var promise = '';
$scope.search = function() {
if(promise){
$timeout.cancel(promise);
}
promise = $timeout(function() {
//ajax call goes here..
},2000);
};
});
HTML
<input type="search" autocomplete="off" ng-model="keywords" ng-keyup="search()" placeholder="Search...">
Debounced / throttled model updates for angularjs : http://jsfiddle.net/lgersman/vPsGb/3/
In your case there is nothing more to do than using the directive in the jsfiddle code like this:
<input
id="searchText"
type="search"
placeholder="live search..."
ng-model="searchText"
ng-ampere-debounce
/>
Its basically a small piece of code consisting of a single angular directive named "ng-ampere-debounce" utilizing http://benalman.com/projects/jquery-throttle-debounce-plugin/ which can be attached to any dom element. The directive reorders the attached event handlers so that it can control when to throttle events.
You can use it for throttling/debouncing
* model angular updates
* angular event handler ng-[event]
* jquery event handlers
Have a look : http://jsfiddle.net/lgersman/vPsGb/3/
The directive will be part of the Orangevolt Ampere framework (https://github.com/lgersman/jquery.orangevolt-ampere).
Just for users redirected here:
As introduced in Angular 1.3 you can use ng-model-options attribute:
<input
id="searchText"
type="search"
placeholder="live search..."
ng-model="searchText"
ng-model-options="{ debounce: 250 }"
/>
I believe that the best way to solve this problem is by using Ben Alman's plugin jQuery throttle / debounce. In my opinion there is no need to delay the events of every single field in your form.
Just wrap your $scope.$watch handling function in $.debounce like this:
$scope.$watch("searchText", $.debounce(1000, function() {
console.log($scope.searchText);
}), true);
Another solution is to add a delay functionality to model update. The simple directive seems to do a trick:
app.directive('delayedModel', function() {
return {
scope: {
model: '=delayedModel'
},
link: function(scope, element, attrs) {
element.val(scope.model);
scope.$watch('model', function(newVal, oldVal) {
if (newVal !== oldVal) {
element.val(scope.model);
}
});
var timeout;
element.on('keyup paste search', function() {
clearTimeout(timeout);
timeout = setTimeout(function() {
scope.model = element[0].value;
element.val(scope.model);
scope.$apply();
}, attrs.delay || 500);
});
}
};
});
Usage:
<input delayed-model="searchText" data-delay="500" id="searchText" type="search" placeholder="live search..." />
So you just use delayed-model in place of ng-model and define desired data-delay.
Demo: http://plnkr.co/edit/OmB4C3jtUD2Wjq5kzTSU?p=preview
I solved this problem with a directive that basicly what it does is to bind the real ng-model on a special attribute which I watch in the directive, then using a debounce service I update my directive attribute, so the user watch on the variable that he bind to debounce-model instead of ng-model.
.directive('debounceDelay', function ($compile, $debounce) {
return {
replace: false,
scope: {
debounceModel: '='
},
link: function (scope, element, attr) {
var delay= attr.debounceDelay;
var applyFunc = function () {
scope.debounceModel = scope.model;
}
scope.model = scope.debounceModel;
scope.$watch('model', function(){
$debounce(applyFunc, delay);
});
attr.$set('ngModel', 'model');
element.removeAttr('debounce-delay'); // so the next $compile won't run it again!
$compile(element)(scope);
}
};
});
Usage:
<input type="text" debounce-delay="1000" debounce-model="search"></input>
And in the controller :
$scope.search = "";
$scope.$watch('search', function (newVal, oldVal) {
if(newVal === oldVal){
return;
}else{ //do something meaningful }
Demo in jsfiddle: http://jsfiddle.net/6K7Kd/37/
the $debounce service can be found here: http://jsfiddle.net/Warspawn/6K7Kd/
Inspired by eventuallyBind directive http://jsfiddle.net/fctZH/12/
Angular 1.3 will have ng-model-options debounce, but until then, you have to use a timer like Josue Ibarra said. However, in his code he launches a timer on every key press. Also, he is using setTimeout, when in Angular one has to use $timeout or use $apply at the end of setTimeout.
Why does everyone wants to use watch? You could also use a function:
var tempArticleSearchTerm;
$scope.lookupArticle = function (val) {
tempArticleSearchTerm = val;
$timeout(function () {
if (val == tempArticleSearchTerm) {
//function you want to execute after 250ms, if the value as changed
}
}, 250);
};
I think the easiest way here is to preload the json or load it once on$dirty and then the filter search will take care of the rest. This'll save you the extra http calls and its much faster with preloaded data. Memory will hurt, but its worth it.

Kendo UI - Placeholder - Style

I have a Kendo UI datepicker with placeholder data. Here is the HTML:
<input type="text" class="datepicker"' placeholder="yyyy-mm-dd" />
Here is the JavaScript:
var start = $(".datepicker").kendoDatePicker({
format: "yyyy-MM-dd",
parseFormats: ["MM/dd/yyyy"],
change: startChange
}).data("kendoDatePicker");
The Kendo UI datepicker displays the placeholder data in the same style as user entered data. I would like to style the placeholder data differently. Specifically, I would like the text to be gray and italicized. When user enters data, the style changes to solid black (non-italicized). Any thoughts on how to do this?
Well, placeholder is an HTML5 attibute and isn't specic to Kendo controls. As I understand it Kendo doesn't offer any support for placeholder over what is supported by the browser, and remember that only some browsers support this attribute; IE does not.
Anyway, to style the placeholder you'll have to use vendor prefix CSS properties, see here.
I use this..it will work on your HTML and you can style it too :)
<script>
// This adds 'placeholder' to the items listed in the jQuery .support object.
jQuery(function() {
jQuery.support.placeholder = false;
test = document.createElement('input');
if('placeholder' in test) jQuery.support.placeholder = true;
});
// This adds placeholder support to browsers that wouldn't otherwise support it.
$(function() {
if(!$.support.placeholder) {
var active = document.activeElement;
$(':text').focus(function () {
if ($(this).attr('placeholder') != '' && $(this).val() == $(this).attr('placeholder')) {
$(this).val('').removeClass('hasPlaceholder');
}
}).blur(function () {
if ($(this).attr('placeholder') != '' && ($(this).val() == '' || $(this).val() == $(this).attr('placeholder'))) {
$(this).val($(this).attr('placeholder')).addClass('hasPlaceholder');
}
});
$(':text').blur();
$(active).focus();
$('form:eq(0)').submit(function () {
$(':text.hasPlaceholder').val('');
});
}
});
</script>

Resources