Make AlpineJS recognize changes to objects - javascript

I'm using AlpineJS and momentjs. The user can add a bunch of datetimes and those get pushed to an array. This array is rendered to the page with an x-for.
Now I want a method setTime, that changes the time of every datetime object. In theory this is pretty easy. But I figured, that AlpineJS will not catch, that something has changed and therefore not re-render the x-for.
I'm using this.dates.map(item => item.hour(10).minute(0)); in my example here: https://jsfiddle.net/suny1vj9/
Is there a way to tell AlpineJS to rerender, since I know when this needs to be rerendered?
I also thought about having the data twice. One as moment/Date object, and one as the string representation. That solves the problem too, but I feel like there has to be a prettier solution than maintaining two similar arrays and keeping them in sync.
How would you solve this problem differently?

It's a known issue with MomentJS mutability. And since any change in the object replaces the original object, Alpine.js cannot detect the change. To fix it, you will have to clone() the original object after setting the hour and minutes, so that Alpine.js can detect that the object has been changed (I mean it's a new object that time)
Also, the map() function returns the new Array, so you need to change your code like this.
function test() {
return {
dates: [
moment("2022-04-23"),
moment("2022-04-25"),
moment("2022-04-26"),
moment("2022-04-27"),
moment("2022-04-28")],
setTime() {
this.dates = this.dates.map((item) => item.hour(10).minute(0).clone())
},
}
}
This will solve your problem :)
Here is the fiddle link https://jsfiddle.net/tujfyhs2/1/

Related

d3.timer update dispatches multiple times

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));

Angular 2 mysteriously modifies all sub-nested similar object within an object with the same value

As can be seen in the example at https://plnkr.co/edit/YyTPVQ?p=preview (Once loaded the app click on any of the names on the left bar)
If I modify any user's scale it also modifies the other user too.
Don't ask me why but, I somehow managed to fix it by deleting all .map and .js files, committed the fix to git, woke up this morning and now it doesn't work AGAIN (YES is a miraculous as it sounds!) https://github.com/thurft/appraisal
My problem is as follows the employees.component.ts handles the logic of employees.component.html
When I rate a question it modifies the same question of all this.employee instead of only doing it for this.selectedEmployee. This would be triggered updateQuestionRequest(question) and there is a console.log(this.employees) to show the Objects being modified.
In no way I modify this.employees array, so Angular somehow knows that it needs to modify the object in the array. But it also modifies all objects in that array that have the same question.
The question/problem is: How can I save the selectedEmployee rated question in the selectedEmployee OBJ instead of the value being saved across all employees OBJ?
I can't tell if is a bug on Angular or is a problem in my code, as sometimes it work, sometimes it doesn't and there is no consistency.
You have to clone TECHNICALQUESTIONS otherwise all employees will share the same reference:
employee[i].technicalQuestions = TECHNICALQUESTIONS.map(_=>{return Object.assign({}, _)};);
Because of Chrome not implmenenting yet the Object.assign the work around is to create a new json file to force the create of a new object employee[i].technicalQuestions = JSON.parse(JSON.stringify(TECHNICALQUESTIONS));

KnockoutJS: Stop a particular property from setting dirty flag

With some help from StackOverflow community I was able to get my dirty flag implementation to work, based on this example: http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html
It does exactly what I want, except for a single use case that I don't know how to solve.
Basically I have a select menu that gets automatically populated from the database. This select menu also has an option to make an Ajax call to my back end and have the list of options refreshed, database updated and return the result. This is where things get hairy for me.
First method works fine, however, it has to re-index and re-apply my entire viewModel and takes about 2-3 seconds, running on a local machine with 16gigs of ram and SSD.
jsondata.component.available_tags = result.available_tags;
ko.mapping.fromJS(jsondata, viewModel);
Second method also works, and pretty much instantaneous, however, it sets of isDirty() flag, which I would like to avoid, because this data is already coming from the database and I wont need to save it. I can not use isDirty.reset() method either, because if isDirty was set by something else before I clicked an menu option to update available_tags, it will reset that too. Which I would also like to avoid.
viewModel().component.available_tags(result.available_tags);
My question is: With the first method, can I force UI refresh with ko.mapping.fromJS() on a particular element and not entire dataset? Or, with a second method, can I avoid setting isDirty flag set when available_tags are updated? The twist is that I still need to keep available_tags as an observable, so the select menu is automatically generate/updated.
UPDATE: I was able to update mapping for that one single element with
ko.mapping.fromJS(result.available_tags, {}, viewModel().component.available_tags);
but that immediately set off isDirty flag... Argh
In addition to Tomalak's suggestions, which I totally agree with, maybe the toJSON method can help you out in similar cases where you don't want to split the model. If your dirty flag implementation uses ko.toJSON as a hash function, as Ryan Niemeyer's does, you can give your model (on which the dirty flag is active) a toJSON method, where you do something like this:
function MyObjectConstructor() {
this.someProperty = ko.observable();
this.somePropertyNotUsedInDirtyFlag = ko.observable();
}
MyObjectConstructor.prototype.toJSON = function () {
var result = ko.toJS(this);
delete result.somePropertyNotUsedInDirtyFlag;
return result;
};
Please be aware that this is also used to serialize the object in some other occassions, such as ajax calls. It's generally a handy function for removing computeds and such from your objects before using them in a different context.

EmberJS: Bind input value to Controller property and run filter on change

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.

KnockoutJS: Update/Insert data to a viewModel using mapping

I've been trying to figure this out for quite some time now. I couldn't find anything that addresses this problem, but please correct me if I'm wrong.
The problem:
I have data from a JSON API comming in, with an nested array/object structure. I use mapping to initially fill the model with my data. To update this, I want to extend the model if new data arrives, or update the existing data.
As far as I found out, the mapping option key, should do this trick for me, but I might have misunderstood the functionality of the mapping options.
I've boiled down the problem to be represented by this example:
var userMapping = {
key: function(item) {
return ko.utils.unwrapObservable(item.id);
}
};
// JSON call replaced with values
var viewModel = {
users: ko.mapping.fromJS([], userMapping)
};
// Should insert new - new ID?
ko.mapping.fromJS([{"id":1,"name":"Foo"}, {"id":2,"name":"Bar"}], userMapping, viewModel.users);
// Should only update ID#1 - same ID?
ko.mapping.fromJS([{"id":1,"name":"Bat"}], userMapping, viewModel.users);
// Should insert new - New ID?
ko.mapping.fromJS([{"id":3,"name":"New"}, {"id":4,"name":"New"}], userMapping, viewModel.users);
ko.applyBindings(viewModel);​
Fiddle: http://jsfiddle.net/mikaelbr/gDjA7/
As you can see, the first line inserts the data. All good. But when I try to update, it replaces the content. The same for the third mapping; it replaces the content, instead of extening it.
Am I using it wrong? Should I try to extend the content "manually" before using mapping?
Edit Solution:
I solved this case by having a second helper array storing all current models. On new data i extended this array, and updated the view model to contain the accumulated items.
On update (In my case a WebSocket message), I looped through the models, changed the contents of the item in question, and used method valueHasMutated() to give notice of changed value to the Knockout lib.
From looking at your example code the mapping plugin is behaving exactly as I would expect it to. When you call fromJS on a collection you are effectively telling the mapping plugin this is the new contents of that collection. For example:
On the second line, How could it know whether you were updating or whether you had simply removed id:2?
I can't find any mention of a suitable method that treats the data as simply an update, although you could add one. Mapped arrays come with some helpful methods such as mappedIndexOf to help you find particular items. If you receive an update data set simply loop through it, find the item and update it with a mapping.fromJS call to that particular item. This can easily be generalized into reusable method.
You can use ko.mapping.updateFromJS() to update existing values. However, it does not add new values so that would be a problem in your instance. Take a look at the link below for more details.
Using updateFromJS is replacing values when it should be adding them
Yes, you should first collect all data into a list or array and then apply the mapping to that list. Otherwise you are going to overwrite the values in your viewModel.

Categories