I am using https://github.com/NejcZdovc/ng2-select2 angular component to handle a pulldown that gets its data from a remote api. The initial list of data that gets populated works fine and I have no problem selecting any of the options in the pulldown, but if I cause the select2 component to have to get data a second time from the api I am not able to select one of the items in the list of options and the previous selection remains selected. Here is some screen show of what is happening.
initial load
Here I select dev1-access-est-1 and the screen looks like.
So far so good.
Now I try to change selection to dhcp-hkg1-1-6
But when I click on dhcp-hkg1-1-6 the Filter Key value remains dev1-access-est-1.
Here is the template HTML I am using for the select2 component:
<div class="form-group__text ">
<select2 name="cm_select2" id="cm_select2" [value]="filterKey" [options]="select2Options"></select2>
</div>
And here is where I am setting my select2Options:
setSelect2Options () {
this.select2Options = {
'width': '100%',
'minimumInputLength': 3,
'ajax': {
'url': function(params) {
var d = new Date(),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
var startDate = [year, month, day].join('-');
var url = "http://dev-03.example.com/api/v1/cm/cm_list/?cm_type=" + $( "#node" ).val() + "&start_date=" + startDate + '&source=mongo';
return url;
},
'dataType': 'json',
'data': function (params) {
var query = { 'starts_with': params.term, 'page': params.page || 1 };
// Query parameters will be ?search=[term]&page=[page]
return query;
},
'processResults': function (data) {
var results = [];
for (var i = 0; i < data.results.length; i++ ) { results.push( { "id": i, "text": data.results[i]} ); }
// Tranforms the top-level key of the response object from 'items' to 'results'
return { 'results': results };
}
}
};
}
Can you please try adding cache: false to the options
'ajax': {
'cache': false,
'url': function(params) {
var d = new Date(),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
var startDate = [year, month, day].join('-');
var url = "http://dev-03.example.com/api/v1/cm/cm_list/?cm_type=" + $( "#node" ).val() + "&start_date=" + startDate + '&source=mongo';
return url;
},
I found the problem got worse with each access to the remote API. On the second call to the remote API I could not select two options from the list. I read the issue I pointed out in my comment above and realized that one cannot reuse id's from one call to the backend API to the next so I decided to add the epoch time to each id in my processResults() function like so:
'processResults': function (data) {
var results = [];
const epochTime = (new Date).getTime();
// work around for issue https://github.com/NejcZdovc/ng2-select2/issues/136 (use epoch time to get unique ids.
for (var i = 0; i < data.results.length; i++ ) { results.push( { "id": i + epochTime, "text": data.results[i]} ); }
// Tranforms the top-level key of the response object from 'items' to 'results'
return { 'results': results };
}
If some finds a better solution please post it here.
Related
So I am trying to store the date inside a database and to do so I need to pass the variable 'date' to the PHP file store.pro.php however, I am not sure how to do this. I have tried Ajax but at the moment it doesn't seem to be working.
Javascipt code:
// variables for fetching current date
n = new Date();
y = n.getFullYear();
m = n.getMonth() + 1;
d = n.getDate();
// variables for displaying current date
let displayDay = 0;
let displayMonth = 0;
// If m or d are only one digit, add a leading 0 to the value
if (d < 10) {
displayDay = '0' + d.toString();
} else {
displayDay = d.toString();
}
if (m < 10) {
displayMonth = '0' + m.toString();
} else {
displayMonth = m.toString();
}
// storing the current date within raceDate
var date = displayDay + '/' + displayMonth + '/' + y;
$.ajax({
url: "processes/store.pro.php",
type: "POST",
data: { x: date }
});
PHP code in store.pro.php
if (isset($_POST['x'])) {
$raceDate = $_POST['x'];
echo($raceDate);
} else {
echo "no";
}
How do you know "it doesn't seem to be working" ?
add success method to your ajax, like this:
$.ajax({
url: "processes/store.pro.php",
type: "POST",
data: { x: date },
success: function(res) {
res = JSON.parse(res);
console.log(res);
}
});
Then, in store.pro.php put this:
if (isset($_POST['x'])) {
$raceDate = $_POST['x'];
echo json_encode($raceDate);
} else {
echo json_encode("no");
}
exit; // You may need remove this line, after you check, that ajax call is working
and check console in your browser
I'm using a tableau web connector to download stock price. The source code is following:
<html>
<meta http-equiv="Cache-Control" content="no-store" />
<head>
<title>Stock Quote Connector-Tutorial</title>
<script src="https://connectors.tableau.com/libs/tableauwdc-1.1.1.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
(function() {
function buildUri(tickerSymbol, startDate, endDate) {
var startDateStr = getFormattedDate(startDate);
var endDateStr = getFormattedDate(endDate);
var queryStatement = 'select * from yahoo.finance.historicaldata where symbol = "' +
tickerSymbol +
'" and startDate = "' + startDateStr +
'" and endDate = "' + endDateStr + '"';
var uri = 'http://query.yahooapis.com/v1/public/yql?q=' +
encodeURIComponent(queryStatement) +
"&env=http%3A%2F%2Fdatatables.org%2Falltables.env&format=json";
return uri;
}
function getFormattedDate(date) {
// Return a date in the format YYYY-MM-DD
return date.getUTCFullYear() +
'-' +
makeTwoDigits(date.getUTCMonth() + 1) +
'-' +
makeTwoDigits(date.getUTCDate());
}
function makeTwoDigits(num) {
// Pad a digit to be two digits with leading zero
return num <= 9 ? "0" + num.toString() : num.toString();
}
var myConnector = tableau.makeConnector();
myConnector.getColumnHeaders = function() {
var fieldNames = ['Ticker', 'Day', 'Close'];
var fieldTypes = ['string', 'date', 'float'];
tableau.headersCallback(fieldNames, fieldTypes);
}
myConnector.getTableData = function(lastRecordToken) {
var dataToReturn = [];
var hasMoreData = false;
// Get parameter values and build YQL query
var ticker = tableau.connectionData;
var endDate = new Date();
var startDate = new Date();
startDate.setYear(endDate.getFullYear() - 1);
//startDate.setYear(startDate.getFullYear() - 1);
//startDate.setYear(startDate.getFullYear() - 1);
//startDate.setYear(startDate.getFullYear() - 1);
var connectionUri = buildUri(ticker, startDate, endDate);
var xhr = $.ajax({
url: connectionUri,
dataType: 'json',
success: function (data) {
if (data.query.results) {
var quotes = data.query.results.quote;
var ii;
for (ii = 0; ii < quotes.length; ++ii) {
var entry = {'Ticker': quotes[ii].Symbol,
'Day': quotes[ii].Date,
'Close': quotes[ii].Close};
dataToReturn.push(entry);
}
tableau.dataCallback(dataToReturn, lastRecordToken, false);
}
else {
tableau.abortWithError("No results found for ticker symbol: " + ticker);
}
},
error: function (xhr, ajaxOptions, thrownError) {
tableau.log("Connection error: " + xhr.responseText + "\n" + thrownError);
tableau.abortWithError("Error while trying to connect to the Yahoo stock data source.");
}
});
}
tableau.registerConnector(myConnector);
})();
$(document).ready(function() {
$("#submitButton").click(function() {
var tickerSymbol = $('#ticker').val().trim();
if (tickerSymbol) {
tableau.connectionName = "Stock Data for " + tickerSymbol;
tableau.connectionData = tickerSymbol;
tableau.submit();
}
});
});
</script>
</head>
<body>
<p>Enter a stock ticker symbol: <input type="text" id="ticker" /></p>
<p><button type="button" id="submitButton">Get the Data</button></p>
</body>
</html>
The code is workable when we just want to download 1 year data, but if we change the time longer than 1 year(enddate.year - startdate.year > 1), it is not workable.
After debugging the code, I found the issue comes from YQL query:
http://query.yahooapis.com/v1/public/yql?q=select * from yahoo.finance.historicaldata where symbol = "AAPL" and startDate = "2014-08-24" and endDate = "2016-11-23"&env=http%3A%2F%2Fdatatables.org%2Falltables.env&format=json
when startDate = "2014-08-24" and endDate = "2016-11-23" is longer than 15 month, YQL will return null. I'm trying to fix this issue. If it is python or java, the problem is not hard, first check whether the duration is longer than 1 year, if so, get 1 year result and do the same for rest n-1 year. But this tableau code makes me stuck with it. I have to make the code workable with tableau, which makes me unable to proceed due to lack of knowledge about both js and tableau.
Can any one advise on this issue? My objective is to make the code workable for >10 years for stock symbol like AAPL.
Thanks in advance.
I don't believe YQL supports queries for longer than 15 months or so. Limits like these are fairly common when working with APIs. What you want to do from a web data connector standpoint is to implement paging.
The high level idea is that your getTableData function of your WDC will execute multiple times, and each time, it will gather a single page of data, which is then passed to Tableau. For example, here's how you could get multiple years worth of data in your example:
myConnector.getTableData = function(lastRecordToken) {
var dataToReturn = [];
var hasMoreData = false;
// Get parameter values and build YQL query
var ticker = tableau.connectionData;
var endDate = new Date();
var startDate = new Date();
var maxYear = 5;
var yearOffset = lastRecordToken || 0;
endDate.setYear(endDate.getFullYear() - (yearOffset));
startDate.setYear(endDate.getFullYear() - 1);
var connectionUri = buildUri(ticker, startDate, endDate);
var xhr = $.ajax({
url: connectionUri,
dataType: 'json',
success: function (data) {
if (data.query.results) {
var quotes = data.query.results.quote;
var ii;
for (ii = 0; ii < quotes.length; ++ii) {
var entry = {'Ticker': quotes[ii].Symbol,
'Day': quotes[ii].Date,
'Close': quotes[ii].Close};
dataToReturn.push(entry);
}
var hasMoreData = !(yearOffset == maxYear);
tableau.dataCallback(dataToReturn, yearOffset + 1, hasMoreData)
}
else {
tableau.abortWithError("No results found for ticker symbol: " + ticker);
}
},
error: function (xhr, ajaxOptions, thrownError) {
tableau.log("Connection error: " + xhr.responseText + "\n" + thrownError);
tableau.abortWithError("Error while trying to connect to the Yahoo stock data source.");
}
});
}
tableau.registerConnector(myConnector);
})();
This example uses the two extra parameters of the dataCallback function to implement paging. The documentation for paging in v1 of the web data connector API can be found here: http://onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_paging.htm%3FTocPath%3DAdditional%2520Concepts%7C_____2
Additionally, if you are able to use v2 of the WDC API (usable in Tableau 10 and later), I would highly recommend it. The paging model in V2 is more flexible and easier to use.
I would like to create a simple if / else statement with JS. That would check if a div element has changed, before populating JSON data fields / variables that pull from dynamically changed HTML.
I do not want to use the DOMSubtreeModified. As it's depreciated..
Below is the started logic, I have. But it looks like I'll have to scrap the DOMSubtreeModified out for a method that is not depreciating.
The question / problem is: How to re-write not using the above depreciated technique, and how to nest my data array, where it will only pull / populate based on first checking my if (condition) Cheers for any pointers.
var element = document.querySelector('.username'); // username div wrapper
//if {
element.addEventListener('DOMSubtreeModified', function() { // detect if div element changes
var date = new Date();
var month = date.getUTCMonth() + 1;
var day = date.getUTCDate();
var year = date.getUTCFullYear();
var time = date.toLocaleTimeString();
var formattedDate = month + '/' + day + '/' + year;
console.log(time); // 7:01:21 PM
console.log(formattedDate); // 3/15/2016
}, false);
// change something on element
setTimeout(function() {
element.dataset.username = 'bar';
}, 3000);
// json object with captured data fields
var NewUserSession = [{
currentusername: $('.username').text(),
referrer: document.referrer,
loggedintime: $(formattedDate),
}];
//}
//
//else {
//
//
//}
You can use MutationObserver and watch for data-username changes
var element = document.querySelector('.username'); // username div wrapper
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName = 'data-username') {
var date = new Date();
var month = date.getUTCMonth() + 1;
var day = date.getUTCDate();
var year = date.getUTCFullYear();
var time = date.toLocaleTimeString();
var formattedDate = month + '/' + day + '/' + year;
snippet.log(time); // 7:01:21 PM
snippet.log(formattedDate); // 3/15/2016
}
});
});
var config = {
attributes: true,
attributeFilter: ['data-username']
};
// pass in the target node, as well as the observer options
observer.observe(element, config);
// change something on element
setTimeout(function() {
element.dataset.username = 'bar';
}, 1000);
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
<div class="username"></div>
Iam using a jquery multiple datepicker calendar. When i go to month of april and clicks the date, the datepicker restores to march.
var lastMDPupdate = '2012-03-28';
$(function() {
// Version //
//$('title').append(' v' + latestMDPver);
$('.mdp-version').text('v' + latestMDPver);
$('#mdp-title').attr('title', 'last update: ' + lastMDPupdate);
// Documentation //
$('i:contains(type)').attr('title', '[Optional] accepted values are: "allowed" [default]; "disabled".');
$('i:contains(format)').attr('title', '[Optional] accepted values are: "string" [default]; "object".');
$('#how-to h4').each(function () {
var a = $(this).closest('li').attr('id');
$(this).wrap('<'+'a href="#'+a+'"></'+'a>');
});
$('#demos .demo').each(function () {
var id = $(this).find('.box').attr('id') + '-demo';
$(this).attr('id', id)
.find('h3').wrapInner('<'+'a href="#'+id+'"></'+'a>');
});
// Run Demos
$('.demo .code').each(function() {
eval($(this).attr('title','NEW: edit this code and test it!').text());
this.contentEditable = true;
}).focus(function() {
if(!$(this).next().hasClass('test'))
$(this)
.after('<button class="test">test</button>')
.next('.test').click(function() {
$(this).closest('.demo').find('.box').removeClass('hasDatepicker').empty();
eval($(this).prev().text());
$(this).remove();
});
Js fiddle link added.
http://jsfiddle.net/bJ7zj/#update
Thanks in advance
The issue seems to be jQuery UI defaulting to today's date when it can't parse several dates.
If you wont use , in your dates or plan on updated jQuery UI very soon, you can use the following fixhack which adds dates = dates.split(',').pop(), allowing the parser to parse the last date in the list when showing the control. You can put this code any place after the jQuery UI reference
$.datepicker._setDateFromField= function (inst, noDefault)
{
if (inst.input.val() == inst.lastVal)
{
return;
}
var dateFormat = this._get(inst, 'dateFormat');
var dates = inst.lastVal = inst.input ? inst.input.val() : null;
dates = dates.split(',').pop()
var date, defaultDate;
date = defaultDate = this._getDefaultDate(inst);
var settings = this._getFormatConfig(inst);
try
{
date = this.parseDate(dateFormat, dates, settings) || defaultDate;
} catch (event)
{
this.log(event);
dates = (noDefault ? '' : dates);
}
inst.selectedDay = date.getDate();
inst.drawMonth = inst.selectedMonth = date.getMonth();
inst.drawYear = inst.selectedYear = date.getFullYear();
inst.currentDay = (dates ? date.getDate() : 0);
inst.currentMonth = (dates ? date.getMonth() : 0);
inst.currentYear = (dates ? date.getFullYear() : 0);
this._adjustInstDate(inst);
};
I have this code that updates a calendar widget and input field, while validating the date. We want the user to be able to input any type of m-d-y format (m.d.y, m-d-y, and so on). The problem is the YUI calendar widget only accepts the m/d/y format. All others it returns as NaN. I have tried a couple ways to format the date, but can't get anything that seems to work. I would like to be able to do this with out a lot of overblown code. Does anyone have any suggestions as to the best approach here? Here is my code:
//CALENDAR --------------------------------------------------------------------------------
var initCal = function(calendarContainer){
if(YAHOO.env.getVersion("calendar")){
var txtDate = Dom.get("dateOfLoss");
var myDate = new Date();
var day = myDate.getDate();
var month = myDate.getMonth() +1;
var year = myDate.getFullYear() -1;
var newDate = month + "/" + day + "/" + year;
function handleSelect(type, args, obj){
var dates = args[0];
var date = dates[0];
var year = date[0], month = date[1], day = date[2];
txtDate.value = month + "/" + day + "/" + year;
aCal.hide();
}
function updateCal(){
if (!(txtDate.value.match(/((\d{2})|(\d))\/|\-((\d{2})|(\d))\/|\-((\d{4})|(\d{2}))/))) {
alert("Enter date in mm/dd/yy or mm/dd/yyyy format.");
}
else {
if (txtDate.value != "") {
aCal.select(txtDate.value);
var selectedDates = aCal.getSelectedDates();
if (selectedDates.length > 0) {
var firstDate = selectedDates[0];
aCal.cfg.setProperty("pagedate", (firstDate.getMonth() + 1) + "/" + firstDate.getFullYear());
aCal.render();
}
else {
alert("Date of Loss must be within the past year.");
}
}
}
}
var aCal = new YAHOO.widget.Calendar(null, calendarContainer, {
mindate: newDate,
maxdate: new Date(),
title: "Select Date",
close: true
});
aCal.selectEvent.subscribe(handleSelect, aCal, true);
aCal.render();
Event.addListener("update", "click", updateCal);
Event.addListener(txtDate, "change", function(e){
updateCal();
});
// Listener to show the 1-up Calendar when the button is clicked
// Hide Calendar if we click anywhere in the document other than the calendar
Event.on(document, "click", function(e){
var el = Event.getTarget(e);
if(Dom.hasClass(el, "calendarButton"))
aCal.show();
else if (Dom.hasClass(el, "link-close") || !Dom.isAncestor(calendarContainer, el))
aCal.hide();
});
}
else {
var successHandler = function() {
initCal(calendarContainer);
};
OURPLACE.loadComponent("calendar", successHandler);
}
};
Did you tried http://www.datejs.com/?
Maybe you can define some patterns and test agaist the input.
How can I convert string to datetime with format specification in JavaScript?
var updateCal = function(){
if (!(txtDate.value.match(/^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.]\d\d+$/))) {
return;
}
//else if ((txtDate.value.match(/^(0?[1-9]|1[012])[- .](0?[1-9]|[12][0-9]|3[01])[- .]\d\d+$/))) {
//}
else {
var changedDate = txtDate.value;
changedDate = changedDate.replace(/[. -]/g, "/");
txtDate.value = changedDate;
badClaimDate = claimDateWithinPastYear();
aCal.select(changedDate);
I used a RegEx to determine which, if any, delimiters needed to be replaced and simply used .replace.