I have a SAPUI5 table. What I want is to provide a text field, where user can enter time interval (like 3 mins), and the table will get refreshed automatically by itself after 3 mins. Moreover, if he provides new value (e.g. 8 mins), table will now get refreshed after 8 mins.
Can anyone give some ideas how can I achieve this? Thanks in advance.
As #sirion said, it depends a little on what table you have, how you want your scroll to behave and so on. I think it is inevitable that your table will "nudge" in some way or another if e.g. new lines get inserted in the table between refreshes or if some lies are deleted.
Nevertheless, I would say that the best option is to get the ListBinding from the table (as sirion said) and do a refresh on this binding:
onRefreshTriggered: function () {
this.byId("myTable").getBinding("items" /* or "rows" */).refresh();
}
It might also be an idea to refresh the element binding for each row, then you would surely not have problems with the scrolling (but you will have problems in case a row is deleted or added).
onRefreshTriggered: function () {
(this.byId("myTable").getItems() || []).forEach(function (oItem){
oItem.getElementBinding(/* model name */).refresh();
});
}
For doing the periodical triggering part, I would use the sap.ui.core.IntervalTrigger class. It is fairly easy to use:
// e.g. in onInit:
this._trigger = new IntervalTrigger(3 * 60 * 1000 /* initial interval */)
this._trigger.addListener(this.onRefreshTriggered, this);
// in a separate method, e.g. as a input field change event
onIntervalChange: function(oEvent) {
var iInterval = parseInt(oEvent.getSource().getValue(), 10);
this._trigger.setInterval(iInterval * 60 * 1000);
}
It depends on what kind of table you are using.
You can always just call oTable.getBinding("x").refresh(), with "x" being "items" or "rows". But that might lead to the table forgetting the scroll position if not everything is shown.
So the "real" solution would be to find out what slice of data is currently shown and then read exactly the same data from the back-end again. Using the read-method on the v2.ODataModel, the model stores the fresh data and updates the property bindings in the table as well.
window.setInterval can be used to call functions at a specific time interval.
window.clearInterval can be used to terminate it.
Attach a change handler to your text, clear any existing intervals and start a new interval with the new time.
<Input change="onInputIntervalChange" />
onInputIntervalChange: function(oEvent) {
var sIntervalInMinutes = oEvent.getParameter("newValue");
var iIntervalInMinutes = parseInt(sIntervalInMinutes);
var iIntervalInMillisec = iIntervalInMinutes * 60 * 1000;
window.clearInterval(this._intervalId);
this._intervalId = window.setInterval(function(){
// refresh your table
}.bind(this), iIntervalInMillisec);
}
Keep in mind that the first refresh will happen after the time interval has passed. If you want to refresh the table immediately when the user changes the value, call your refresh method directly before setInterval.
Related
I'm using Leaflet for a mobile app developed with Ionic. I currently have a function to search for certain items near a location specified when you make a single click on the map
$rootScope.map.on('click', function(e) {
if (APP_STATUS == ACTION_SEARCH) {
positionClick = e.latlng;
$scope.positionSearchClose = positionClick;
$scope.userPosition.setLatLng(positionClick);
$scope.popupSearchRoutesClosed = $ionicPopup.show({
template: $scope.getTemplate(),
title: 'Buscando rutas',
scope: $scope,
});
$scope.getRoutesClose(positionClick, ACTION_SEARCH);
}
});
$scope.addButtons();
I want to change this so that the search happens when the user holds the touch for a brief time. I changed the 'click' parameter to 'contextmenu' and I achieved what I was looking for, but I found out that the hold timing was too long. Despite the leaflet doc description of the ContextMenu event being "Also fired on mobile when the user holds a single touch for a second (also called long press)." it feels like that "second" is an eternity.
Is there a way to make it so the function above only triggers when the user holds the touch, but specifying the amount of time of the hold?
it maybe long time. But i've been searching for this for few hours. i found the solution, which may help anyone who comes here.
In leaflet, touch tap delay declared as 1000ms in a settimeout function. And they can be edited.
In leaflet.js find the below code :
// simulate long hold but setting a timeout
this._holdTimeout = setTimeout(bind(function () {
if (this._isTapValid()) {
this._fireClick = false;
this._onUp();
this._simulateEvent('contextmenu', first);
}
}, this), 1000);
now the 1000(1 second) declared here is the timer, you can change the 1000 to whatever you like...like 300 or 500.
if you want to change touch hold(tap) timer dynamically,
create a variable in the leaflet.js beginning
var contextMenuTime = 1000;
and manually apply the variable in js the function
...
this._simulateEvent('contextmenu', first);
}
}, this), contextMenuTime);
now you can control the tap delay by changing the variable value.
I searched a lot for a solution to this certainly-not-unique problem, but I have not found anything that will work in my context of an HTML page.
I have an input text that contains some kind of source-code that generates something, and I can show a preview of that something on the same HTML page (by updating the background image, for example). Note that the source could be a LaTeX file, an email, a Java program, a ray-trace code, etc. The "action" to generate the preview has a certain cost to it, so I don't want to generate this preview at each modification to the source. But I'd like the preview to auto-update (the action to fire) without the user having to explicitly request it.
Another way to phrase the problem is to keep a source and sink synchronized with a certain reasonable frequency.
Here's my solution that's too greedy (updates at every change):
$('#source-text').keyup(function(){
updatePreview(); // update on a change
});
I tried throttling this by using a timestamp:
$('#source-text').keyup(function(){
if (nextTime "before" Now) { // pseudocode
updatePreview(); // update on a change
} else {
nextTime = Now + some delay // pseudocode
}
});
It's better, but it can miss the last updates once a user stops typing in the source-text field.
I thought of a "polling loop" for updates that runs at some reasonable interval and looks for changes or a flag meaning an update is needed. But I wasn't sure if that's a good model for an HTML page (or even how to do it in javascript).
Use setTimeout, but store the reference so you can prevent it from executing if further editing has occurred. Basically, only update the preview once 5 seconds past the last keystroke has passed (at least in the below example).
// maintain out of the scope of the event
var to;
$('#source-text').on('keyup',function(){
// if it exists, clear it and prevent it from occuring
if (to) clearTimeout(to);
// reassign it a new timeout that will expire (assuming user doesn't
// type before it's timed out)
to = setTimeout(function(){
updatePreview();
}, 5e3 /* 5 seconds or whatever */);
});
References:
clearTimeout
setTimeout
And not to self-bump, but here's another [related] answer: How to trigger an event in input text after I stop typing/writing?
I tweaked #bradchristie's answer, which wasn't quite the behavior I wanted (only one update occurs after the user stops typing - I want them to occur during typing, but at a throttled rate).
Here's the solution (demo at http://jsfiddle.net/p4u2mhb9/3/):
// maintain out of the scope of the event
var to;
var updateCount = 0;
var timerInProgress = false;
$('#source-text').on('keyup', function () {
// reassign a new timeout that will expire
if (!timerInProgress) {
timerInProgress = true;
to = setTimeout(function () {
timerInProgress = false;
updatePreview();
}, 1e3 /* 1 second */ );
}
});
I have a table created from an observable array. Table rows contains elements belonging each to one of a set of categories. To filter the table based on categories, there is a row of buttons.
Buttons can be active or inactive, indicated via a CSS class bound via knockout:
<button data-bind="click: filter.filterCategory, css: { filterOn: filter.category.isFiltered() }">Filter</button>
Filtering within the table is done by switching the display state of rows:
<tr data-bind="css: { nonDisplay: !table.category.isDisplayed() }">
</tr>
The click handler mainly sets the values of the two observables, in sequence e.g.
vm.filter.category.isFiltered(true);
vm.table.category.isDisplayed(false);
This works in principle.
The problem is that the indication that the filter button has been selected by the user is not given immediately, but dependent on the execution time of the filtering itself, i.e. the changes to the table.
With larger tables, and especially on mobile, this can mean delays of a couple of seconds.
I can live with the filtering itself taking this long, but the feedback needs to be immediate.
Is there a way to ensure that the change on vm.filter.category.isFiltered gets applied before the longer running change based on vm.table.category.isDisplayed is started?
This seems as an async fail.
You should implement a callback method parameter in the isFiltered method, something like this
var vm = vm || {};
vm.filter = vm.filter || {};
vm.filter.category = (function($){
var that = this;
that.isFiltered = function(booleanValue, callback) {
// Put your primary code here
console.log("this runs first");
// ...when the first code is done
callback();
};
that.isDisplayed = function(booleanValue) {
console.log("this runs second");
};
return that;
})($);
// Implement by stating a method as the second parameter.
vm.filter.category.isFiltered(true, function(){ vm.filter.category.isDisplayed(false); });
This will render
// this runs first
// this runs second
I have this code here
self.timestamp = ko.observable(data.timestamp);
self.dateFromNow = ko.computed(function ()
{
return moment(self.timestamp()).fromNow();
}, self);
self.timestamp is simply a unix timestamp
self.dateFromNow looks something like 44 years ago or 1 minute ago
My goal is for self.dateFromNow to recompute every set time interval.
These properties are bound to HTML <time> elements but I don't want to do the recomputation by using JS/jQuery to go over the elements and recompute.
I think a better way would be just to simply recalculate the values in KnockoutJS every set time interval and let KO update the markup.
Is there a way to do this in KnockoutJS?
UPDATE: What I did was something like this in lieu of the poster's answer
setInterval(function() {
$.each(self.foo(), function(index, item) {
item.timestamp.notifySubscribers();
});
}, 60 * 1000); // 60 * 1000 milsec
Another way to handle this would be to re-evaluate the computeds whenever another observable changes value, which changes on an interval. Sound crazy?
var fireEvaluations = ko.observable(0);
// Somewhere after the DOM is ready
setInterval(function () {
fireEvaluations(fireEvaluations() + 1);
}, 6000);
var someOtherObservable = ko.computed(function () {
// Subscribe to the triggering observable
if (fireEvaluations()) { }
// Do your real code
});
Now all computeds which have something like if (fireEvaluations()) { } will re-evaluate once that value changes.
Not built into knockout, no (at least, not as far as I know). It has a mechanism (throttling) that limits how often view model changes are propagated through, but obviously that's not what you're after. Arguably you should have a member on your view model that you bind through to your element, and then it's your responsibility to update your view model periodically.
I want to display some data which comes from my db using jQuery.ajax() (i.e. each one contains a title and a description) and I want this process to be done on a regular basis, say setInterval(func, 5000).
Now what I actually need is a js container (an array, a variable, whatever) in which I can store these items to and using another function, I want them to be displayed every 2 seconds.
So, in other words:
We have to have two functions and a container, if you will. The ajax function is fired every 5 seconds and appends its data (if any) into the container (a queue).
On the other hand, the second function displays the content of our container every 2 seconds and removes the displayed items from the container of course.
How can I implement this?
var queue = [];
function ajaxCall() {
$.when($.ajax(...)).done(function(data) {
///assuming your data json's outermost structure is an array
while(data[0]) {
queue.push(data.shift());
}
})
}
function publisher() {
var item = queue.shift();
if(item) {
//do your gubbins here
}
}
setInterval(ajaxCall,5000);
setInterval(publisher, 2000);
Why not using an Array. It can store a string, an object...
Take a look at this great blog post.
If you need queue, this post may help you....
first, set up a container like this one :
<div id="container">
<ul>
</ul>
</div>
then, in your .js :
//step 1. define global Array to hold the values
$(document).ready(function(){
var items = new Array();
//step 3. call the ajax every 5 second
var updateInterval = setInterval(function() {
get_the_data();
//don't forget to empty the array
items = [];
}, 5000);
//step 4. so now, with the data got refresh every 5 second, you just have to append this data into container every 2 second. use the .html method
//logically, in first two times invoke to this method (4 seconds) the container would get same data from array, but in third invocation (at 6 seconds) the container get the fresh one, and so on...
var insertToContainer = setInterval(function() {
for(i=0;i<items.length;i++){
$('#container ul').html('<li>' + items[i] + '</li>')
}
}, 2000);
});
//step 2. set up your ajax call
function get_the_data()
{
$.ajax({
//set your ajax code here...
success:function(data){
//on success put the data into the global array
for(i=0;i<data.length;i++){
items.push(data[i]);
}
}
});
}
I hope this would work for your project. Cheers :-)
PS: frankly speaking, I don't know why you wanted such implementation (i mean, 2 different update functions with different interval value), the more simple way is using just one invocation to the ajax call every 2 seconds as long as display it in container using .html , but it's just my opinion, It should be more complex logic behind your app. :-)