I've tried to keep this as brief as possible, but with enough detail.
I have a yearly calendar which I need to be interactive so that when you click on a date and drag the mouse across to another date, all dates within the current dragged range have their class changed dynamically in a temporary state. An onMouseUp event would then make the temp changes permanent.
The calendar is broken down in to class objects so that:
<Year>
<Month>
<Day>
<Shift {some state values from Year need to be passed here}/>
</Day>
</Month>
</Year>
<Year> contains some functions that changes some states in the constructor for <Year> - namely a start and end date. This function is passed all the way to <Shift> so that when there's an onMouseDown event a the <Shift> level it calls the function in <Year> that sets the start date.
Additionally hovering sets an end date using the same process, so clicking one then dragging across many <Shift /> components will set a start and end date at the <Year> level. When the user is happy with their selection, an onMouseUp event would commit these changes to a permanent display.
This start and end date was intended to be used in each <Shift /> component to determine the CSS class used for rendering for that <Shift>.
Turns out that simply calling the date setting functions slows the whole thing down dramatically and there's massive lag in the drag event, even when I modify the code so that the start and end dates literally do nothing except be stored in <Year>.
It's like I'm re-rendering the whole <Year> component unnecessarily, meaning all others get re-rendered too, but since the start and end dates aren't even being passed anywhere, I don't see how?
Any help on restructuring the work flow would be appreciated.
It sounds like you're constantly updating the state as you're hovering. To avoid that use a debouncer so you only update the state at the end of the hover:
// Shift component
debounceSetEnd(date) {
clearTimeout(this.timer);
this.timer = setTimeout(() => this.props.setEnd(date), 1000);
}
onMouseEnter={() => this.debounceSetEnd(this.props.date)}
The solution was to use PureComopnents instead of Components (or alternatively make use of componentShouldUpdate() with clearly defined logic) and use immuatableJS to ensure I used proper immutable objects... which I clearly had not (shame on me!)
Related
I'm trying to create an on-click event function to render data on specific days.
The onClick function doesn't work properly and renders the data regardless of what day it is, I've tried a lot of different methods like: filter, sort, map and conditional rendering.
I'm a bit of a loss at this point.
What solution or method should I look up in order to get to my end goal?
Here's a part of my repo of where my code is being called: Github
Here's my codesandbox to spare you from details: CodeSandbox
Also here's a demo of what I'm trying to accomplish by another guy's sandbox. CodeSandbox
Thank you so much!
const OnClickDay = (event) => {
console.log("event", event);//this is selected date
// selectedValue is wrong, it is prev selected(click) date
};
onClickDay={(e) => {
OnClickDay(e);
}}
This has been solved by another person! Thanks so much for everyone's input.
For any lost souls that stumbles upon this post... here's what's been forked from a redditor! Answer
There are two approaches:
onclick, filter the events, set the event state, and map them to html
onclick, set the date state, filter and map to html at the same time
Assuming the first solution, your "event" variable is a const, its not
using useState. You'll notice the other guy's has useState for their
"game" variable.
When you call onClick, its just updating a variable to true. You need
to filter the events and update an events state variable.
Post
I've changed an slider to parse JSON data with an start and end date to create a d3.js playback visualization.
My REPL:
https://svelte.dev/repl/69ede1e0f5a74f0c81a1213ce844b9f1 ( slider.svelte -> line 145 function: update() )
What happens is that once a value is rounded to a hour, it dispatches it. but 6-7 values round to the hour so it gets dispatched 6-7 times.
Is there a way to return the function if the hour was already dispatched?
I'm using Svelte
Regards,
Pepijn
You should be able store the already dispatched hours in an array or object and check that one before firing or handling the event. It is rather hard to show with your example because there are a lot of other things going on. If you can simplify it to the pure basics it would be easier.
I solved my problem by adding a variable named "lastDispatch", I set this to the startDate value.
in my update function I wrapped the dispatch function in this check:
if(lastDispatch.getHours() < roundMinutes(new Date(target)).getHours())
and before dispatching I overwrite the variable again
lastDispatch = roundMinutes(new Date(target));
I'm encountering performance issues, I think due to lots of watchers in the page (more than 4000!!). The scenario is a (small, about 5) list of items in ng-repeat once, each one contains another ng-repeat for every day of week (so 7), and in each day container there are 1 or 2 input field. Each day's element has its own scope and controller and some watch at parent's properties, in order to update parent state at child changes. So a bit complex scenario...imagine an agenda view where each day as some input fields or buttons which update same property in the main scope, like "10 days selected/filled/clicked".
I started with about 5000 watchers, now reduced to about 4000 removing some filters and switching to translate-once directive insted of translate (angular-translate).
So the main question is:
How to further reduce the number of watchers?
Is every child scope inheriting the parent watchers, resulting in 7x for each watcher? If I remove child's controllers, leaving the job to the the parent (passing in the function the child item), will I decrease the number of watchers? Could this be a solution? Any help is appreciate.
In our experience that number of watchers cause no speed problems. The performance problems we have encountered in the last 8 months of development on a single big application were caused by slow third part's components.
For example, we have a page with two drag and drop trees with 14.600 watchers (because of high number of items in both trees). We experienced performance problems because of the component used, angular-ui-tree, and we reduced them opening the page with most of the tree collapsed.
We cannot change that component because it is the only one which features drag and drop between trees, but in another page where we had drag & drop between simple lists we have tried those two components: angular-dragdrop and angular-drag-and-drop-lists. The first had a lot of performance problems (with about 500 items) while the second run really really fast. In his documentation on github, section "Why another drag & drop library?" you can read why it is so fast and why the other is so slow.
So, I can speculate that third part's components bring you the real performance problems, and not the watchers.
In any case, we often write our watchers with a check like the one below to not run the code unless needed.
$scope.$watch('variableToWatch', function(newValue, oldValue) {
if (newValue === oldValue) {
return;
}
... watcher code ...
}
Another way to reduce watchers from html is using one-time-binding.
Example:
<div ng-if="::vm.user.loggedIn"></div>
Related to performance... - One pattern i came up with is to use a private object and assign the prototype of a function for easy access. then in any function ,controllers, directives...ect you can access the prototype of other function,controllers,directives easily. instead of using watchers you can use this pattern like a event loop. instead of angular running 300+ watchers every digest cycles. using this pattern only what triggers the function call matters.
An example of this pattern
var private = {} //accesable to entire app
var app = angular.module('some-app',[])
.controller('someCtrl',['$scope',someCtrl])
.directive('someDirective',someDirective);
function someCtrl($scope){
private.someCtrl = someCtrl.prototype
someCtrl.prototype.update = function(someDate){
//do something....
//access to someCtrl arguments
$scope.something = someDate
}
}
function someDirective(){
var someCtrlProto = private.someCtrl;
return{
link:function(scope ,elm ,attr){
elm[0].addEventListener('click',fucntion(){
someCtrlProto.update(someData)
});
//or
elm[0].addEventListener('click',someCtrlProto.update) //to trigger someCtrl.update from here
}
}
}
I want to collect the most recent 10 items from my datastore. I believe I am supposed to do this using .child() and .limitToLast(), which emits an event every time a result has been added to the child.
I don't necessarily know if there are 10 items in total, so a simple counter won't work.
How do I know when Firebase is finished giving me results?
Example lookup code:
var plots = [];
firebaseDatastore.child("plots").orderByChild("unicode-timestamp").limitToLast(10).on("child_added", function(snapshot) {
// Add the new item to the list
plots.push(snapshot.val());
});
I need to know when the final plot has been added, regardless of whether it has hit the limit.
A Firebase query never really ends. It continues to monitor (in your case) the plots by unicode-timestamp and keep a "window" of the last 10 plots.
So:
child_added:timestamp1
child_added:timestamp2
...
child_added:timestamp9
child_added:timestamp10
And then when you add another plot:
child_removed:timestamp1
child_added:timestamp11
If you are not looking to use this behavior, you have two options:
use a value event and then snapshot.forEach over the child nodes
keep a counter and off your listener when you've reached the number of children you expect
I'm trying to bind a input's value to it's controller's property to keep it updated when the property changes. When the input value has changed, I then need to fire a filter method.
I found some examples, but I'm either doing something wrong or they no longer apply as they are a few months old and Ember has gone through some changes.
JSBin: http://emberjs.jsbin.com/oTiKiDI/1/edit
If you were able to manipulate the this.inputDate property directly, as you're doing in your jsbin, I believe it wouldn't properly fire any observers when you change the value. So rather than manipulating this.inputDate.anything, you should this.set('inputDate', [whatever]).
A Date().getDate() returns just the day of the month, not any usable proxy to a Date object, and adding 1 to that value will not add one day to your Date(). I prefer to use http://momentjs.com/ to manipulate dates painlessly and semantically.
http://emberjs.jsbin.com/oKehAYE/3/edit works, and has filterDate pulled out of the actions hash and turned into an observer. If you uncomment the alert() line it will do something when the inputDate changes. It probably doesn't work ideally, since when the page initially renders you have a Date object, and then once you change it you have a Moment—you might as well initialize inputDate with moment(new Date)—but I leave that as an exercise for the reader.