Meteor trigger event on server collection change - javascript

I would like to trigger an event on a meteor server when a document on my collection changes to a specific value, say some field changes from false to true.
I am familiar with binding events to the client; however, I want this event to only be called when the server state changes, specifically the value of a given document in my collection. I want to trigger an external HTTP call from the server when this happens, as I need to message external applications.

Seems like this is an old post. For the benefit of others.
Peerdb package seems to do some of the tasks you are looking for.
https://atmospherejs.com/peerlibrary/peerdb

Also a bit late, but the most classic solution to this type of problem is using the very popular meteor-collection-hooks library. In particular, you'd probably want to use the .after.update hook (click link for full documentation), which allows you to hook into a particular collection after an update is made to a document and compare before and after by comparing doc (doc after update) to this.previous (doc before update).

Related

Using JavaScript to change a React Page Content

So, I have an API that uses Swagger for it's documentation, swagger generates a ReactJs webpage to document and test the API endpoints. I know pretty much nothing about React architecture, So I don't exactly know what is causing this problem:
Before using any endpoint, you have to request a authentication Token, using another endpoint that performs a POST request to another API, that returns the Bearer Token.
Everytime I start the API for test purposes i have make the authorization request "manually" by putting the json in the textarea:
Then I have to grab the token in the response, open the Authorization modal, and paste the token in the input:
And I do that so many times. So i decided to create a little script in JS to make this process to me when i start the API Debugging. And that implies that the script changes the textarea/input values on the swagger page. When the value is changed, you can see it on the UI, but once the script simulates another action, like submitting the request, the changed value returns back to the old/default one.
Looks like it needs user interaction to update the page state?? i don't quite get it, i also tried after changing the values, trigger every change/update js event that i know, but didn't work either.
What exactly React is doing here?
is there a way to fix this?
EDIT: Example of what im doing:
I've installed React Developer Tools as Ray Hatfield suggested, looks like the input is indeed a React Component
Im trying to update the state after I change the value:
But still doesn't work
This is more of a comment than an answer, but…
Is your script changing the textarea value via direct DOM manipulation? e.g. document.querySelector('textarea').value = json? If so, it's likely that React doesn't see it because data/state generally flows downward into the DOM, not upward from the DOM.
My guess is that there's a React component that renders the textarea and registers a change listener on it. Change events from the textarea trigger a state update in the component, which rerenders the textarea to reflect the updated state.
You indicated that you've fired the change event, which seems like it should work given the scenario above. It's possible, though less likely, that the update is triggered via a keydown or keypress.
What I would suggest is that you install the React devtools in your browser and use the "Components" view to inspect the textarea component. It might give you some insights into the state of the component, what events it's listening for, etc., and it would let you see what (if anything) changes when you run your script.
It also includes a button that will open the source code for the selected component. (In minimized apps without sourcemaps it might be impenetrable, but it's worth a look.)
Alright, finally got it, to solve the React component not rerendering, i had to use Javascript's PropertyDescriptor to get the native value setter of the input elements:
var ValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value"
).set;
Then I called the ValueSetter Method passing the Node of the Input Element and it's new value:
ValueSetter.call(authInput, token);
And now just trigger the "Input" event, and for some reason I need to set the bubbling of the event to True, so the event get dispatched on the ancestrals elements (maybe react listen to some wrapper/main element triggers and it's children just bubble the event so it can get to it, idk...):
var inputEvent = new Event("input", { bubbles: true });
authInput.dispatchEvent(inputEvent);

Azure event hub, receive events only after processing previous events?

Im using azure event hub for a project via this npm package #azure/events-hub
Im wondering if theres a way to make the event receiver only receive new event when it is done processing a previously received event. The point is i want to process one event at a time.
My observation currently is that it sends events to the handler the moment they become available.
The api im using is the client.receive(partitionId, onMessage, onError) from the docs.
Wondering if there's a way to achieve the mentioned behaviour, with this api.
The client.receive() method returns a RecieverHandler object that you could use to stop the stream using it's stop() method. You would then start it again using a fresh client.receive().
Another option would be to use client.recieveBatch() where the max batch size is set to 1.
Neither option is ideal- as Peter Bons mentioned, Event Hubs are not designed for a slow drip of data.The service assumes that you will be able to accept messages at the same rate they came in, and that you will have only 1 receiver per partition. Service Bus is indeed a good alternative to look into. You can choose how many messages a recieve at a time and connect multiple receivers, each processing one message at a time, to scale your solution.
What you are describing is the need to have back pressure and the latest version of the #azure/event-hubs package has indeed solved this problem. It ensures that you receive events only after the previously received events are processed. By default, you will receive events in batches of size 10 and this size is configurable.
See the migration guide from v2 to v5 if you need to upgrade your current application to use the latest version of the package.

Multiple distributed event stores for data governance working together

I play around with CQRS/event sourcing for a couple of months now. Currently, I'm having trouble with another experiment I try and hope somebody could help, explain or even hint on another approach than event sourcing.
I want to build a distributed application in which every user has governance of his/her data. So my idea is each user hosts his own event store while other users may have (conditional) access to it.
When user A performs some command this may imply more than one event store. Two examples:
1) Delete a shared task from a tasklist hosted by both event store A and B
2) Adding the reference to a comment persisted in event store A to a post persisted in event store B.
My only solution currently seems to use a process manager attached to each event store, so when an event was added to one event store, a saga deals with applying the event to other related event stores as well.
Not sure what is the purpose of your solution but if you want one system to react on events from another system, after events are saved to the store, a subscription (like catch-up subscription provided by Greg Young's EventStore) publishes it on a message bus using pub-sub and all interested parties can handle this event.
However, this will be wrong if they just "save" this event to their stores. In fact they should have an event handler that will produce a command inside the local service and this command might (or might not) result in a local event, if all conditions are met. Only something that happens within the boundaries, under the local control, should be saved to the local store.

Postpone Synchronize Backbone.js Collection with Server

I have a Backbone Collection that users are performing CRUD-type activities on. I want to postpone any changes from being propagated back to the server — the Collection.sync() should not happen until the user initiates it (like POSTING a form).
As it stands, I have been able to implement on-the-fly updates with no issue (by calling things like Model.destroy() on the models when deleted, or Collection.add() to add new models to the collection. As I understand, I could pass the {silent:true} option to my models, preventing .sync() from being called during .add()/.destroy(), but from what I can tell, that could lead to some headaches later.
I have considered overriding Backbone.sync, but I am not sure if that is the best route — I feel like there is some way to hook into some events, but I am not sure. Of course I have read through the Backbone docs, annotated source, and relevant SO questions before posting this, but I have hit a wall trying to extrapolate for this particular situation.
Eventually I will need to implement this in many places in my application, which is why I am concerned about best-practices at this stage. I am looking for some guidance/suggestions/thoughts on how to proceed with preventing the default behavior of immediately syncing changes with the remote server. Any help is appreciated — thank you for your time!
EDIT:
I went with Alex P's suggestion of refactoring: in my collection I set up some attributes to track the models that have been edited, added, or deleted. Then, when the user triggers the save action, I iterate through the lists and do the appropriate actions.
The first step is to ensure that your collection is being synchronised when you suspect it is. Collection.add() shouldn't trigger a Collection.sync() by default (it's not mentioned in the method documentation or the list of events, and I couldn't see a trigger in the annotated source).
Model.destroy() does trigger a sync(), but that shouldn't be a surprise - it's explicitly defined as "destroying a model on the server", and that sync() is performed on the model, not the collection. Your destroyed models will be removed from any collections that contain them, but I wouldn't expect those collections to sync() unless explicitly asked.
If your collections really are sync()ing when you're not expecting them to, then the most likely culprit is an event listener somewhere. Have you added any event listeners that call sync() for you when they see add or remove events? If your collection should sync() only on user interaction, can you remove those event listeners?
If not, then passing {silent: true} into your methods might be a viable approach. But remember that this is just stopping events from being emitted - it's not stopping that code from running. If something other than an event listener is triggering your sync()s, then preventing those events from being emitted won't stop them.
It would also be worth considering a wider refactor of your app. Right now you modify the collection and models immediately, and try to delay all sync()s until after the user clicks a button. What if you cached a list of all models to destroy & items to add, and only performed the actions when the button is clicked? Storing the model IDs would be sufficient to destroy them, and storing the collection ID and model ID would let you add items. It also means you don't have to fetch() the collection again if the user decides not to save their changes after all.

Instant update backend with Knockoutjs

I am trying to create a web page with form that once user change any field, the validation and update commit immediately rather than letting user to click on submit button. I am using Knockout.js and mapping plugin. I know I can achieve this by creating a computed field for each original fields, but this kind of work is tedius and dumb, is there good practice to create a general listener to listen on any changes in any fields and update backend respectively?
In order to subscribe to any change you could use ko.toJS() method. Actually it allows to walk through object graph and unwrap observables. As your probably know when you use ko.computed it subscribes to all reads of observables fields and re-evaluate on every change. So if you use code like this:
ko.computed(function() {
ko.toJS(viewModel);
// update data on server
});
Also you should pay attention that this piece of code will update data on server right after initialization. It could be easily avoided. Please checkout this example: http://jsfiddle.net/UAxXa/embedded/result/
Also I think you might want to send only changed data to server. You could incorporate ko.editbales plugin ( https://github.com/romanych/ko.editables ) and some KO under-hood knowledge. Please checkout this sample: http://jsfiddle.net/romanych/RKn5k/
I hope it could help you.
You've got several options but if you want a single listener, one good way is to use the same code I used to create a change tracker. It simply listens for the observable changes. Its about 19 lines of code. You can grab this and instead of using it for change tracking, just wire in a method that saves the changes when they occur.
NuGet http://nuget.org/packages/Knockout.ChangeTracker
Codeplex http://kochangetracker.codeplex.com/
To Setup change tracking, add this tracker property to your view model:
viewModel.tracker = new ChangeTracker(viewModel);
Hook these into your view to determine when changes occur:
viewModel.tracker().somethingHasChanged();
Hook this into your view model when you want to reset state in functions (ex: load, save):
viewModel.tracker().markCurrentStateAsClean;
Optionally, you can pass your own hashFunction for state tracking, too.

Categories