View-to-Model formatters in Rivets.js - data-binding

Loving Rivets.js for it's power yet simplicity. However, how to define formatters that take a view-property and format it to a model-property? To my understanding Formatters are meant to operate the other way around, i.e.: from Model to view.
Are View to Model formatters supported somehow, or does this have to be hacked?

This is a feature that was brought in to Rivets.js 0.4.2. Big thanks to GMFlash and mdekmetzian on GitHub for implementing it.
Basically you just define bidirectional formatters as an object instead of a single function. When a formatter is defined as a single function, Rivets assumes it to be in the read direction only. When a formatter is defined as an object, Rivets uses it's read and publish functions to effectively serialize and de-serialize a value.
rivets.formatters.date = {
read: function(value) {
return value.format("DD/MM/YYYY")
},
publish: function(value) {
return moment(value, "DD/MM/YYYY")
}
}
You can also chain bidirectional formatters with any other formatters, and in any order. They read from left to right, and publish from right to left (skipping any read-only formatters when publishing the value back to the model).
Apologies for the lacking documentation. The homepage doesn't reflect at all the current feature set of Rivets.js and needs to be updated to include added features such as this.

Related

Meteor reactive-var package is missing the equals() method, is this a bug?

I'm learning about reactive programming in Meteor:
https://stephenwalther.com/archive/2014/12/05/dont-do-react-understanding-meteor-reactive-programming
I believe that the idea behind Session.equals(key, value) is to remember an association between the reactive variable and the desired value so that updates only propagate to the surrounding code if the equality changes. That way if we have hundreds of views that depend on the variable, only the old and new views get their update code triggered when the value changes.
Note that this would not be the case if we called Session.get(key) === value because every view's code would be called when the variable changes. This is discussed further under the Session.get versus Session.equals() section of the article.
But I found an inconsistency under the Using Reactive Variables section where it says:
Notice that a reactive variable, unlike the Session object, does not have an equals() method. Yes, that is a shame.
So reactive-var is missing equals() but reactive-dict has ReactiveDict.equals().
I can't really see a conceptual reason to exclude ReactiveVar.equals(). Maybe they had no context for storing the association, or maybe there is some scoping or other issue with Javascript that prevents this that I don't fully understand.
So my question is: is this a bug?
Should I just always use reactive-dict? In which case I would change everything from:
let myReactiveVar = new ReactiveVar();
...
if(myReactiveVar.get() === 'myValue')
To the more verbose (but performant):
let myReactiveDict = new ReactiveDict();
...
if(myReactiveDict.equals('myReactiveVar', 'myValue'))
Which would match the functionality provided by Session.equals().
Another option would be to extend the ReactiveVar prototype with my own equals() method or inherit it in a child class and provide a MyReactiveVar.equals() method. Kudos if someone can provide examples to do either of these workarounds that we could submit as a pull request to the Meteor maintainers.
Update: I forgot to mention that ReactiveVar does take an equalsFunc optional parameter in its constructor. It might be possible to hack that as a reactive code block to partially implement equals() functionality without extending the class. Also, here is a related issue on GitHub.
Update: to save time, here is the relevant source code for ReactiveVar and ReactiveDict.equals(). I believe that the value parameter gets converted to serializedValue and is then added as a dependency in ReactiveDict, but I still don't see why it wouldn't be possible to do something similar for ReactiveVar.
The reason there's no equals method for ReactiveVar is because set only invalidates the computations is the new value differs from the current value.
Sets the current value of the ReactiveVar, invalidating the Computations that called get if newValue is different from the old value.
const example = new ReactiveVar(0);
Tracker.autorun(() => {
console.log(example.get());
});
example.set(1); // logs 1
example.set(0); // logs 0
example.set(0); // doesn't log
This is similar behaviour to ReactiveDict's equals method.
Note that set on ReactiveDict does not behave this way. Calling set broadcasts that the value has changed. If you want to prevent the computation from invalidating, that is when you would use equals.
Set a value for a key in the ReactiveDict. Notify any listeners that the value has changed (eg: redraw templates, and rerun any Tracker.autorun computations, that called ReactiveDict.get on this key.)

Meteor - check() VS new SimpleSchema() for verifying .publish() arguments

To ensure the type of the arguments my publications receive, should I use SimpleSchema or check()?
Meteor.publish('todos.inList', function(listId, limit) {
new SimpleSchema({
listId: { type: String },
limit: { type: Number }
}).validate({ listId, limit });
[...]
});
or
Meteor.publish('todos.inList', function(listId, limit) {
check(listId, String);
check (limit, Number);
[...]
});
check() allows you to check data type, which is one thing, but is somewhat limited.
SimpleSchema is much more powerful as it checks all keys in a documents (instead of one at a time) and lets you define not only type but also allowed values, define default (or dynamic) values when not present.
You should use SimpleSchema this way:
mySchema = new SimpleSchema({ <your schema here>});
var MyCollection = new Mongo.Collection("my_collection");
MyCollection.attachSchema(mySchema);
That way, you don't event need to check the schema in methods: it will be done automatically.
Of course it's always good practice to use the
mySchema.validate(document);
to validate a client generated document before inserting it in your collection, but if you don't and your document doesn't match the schema (extra keys, wrong types etc...) SimpleSchema will reject the parts that don't belong.
To check arguments to a publish() function or a Meteor.method() use check(). You define a SimpleSchema to validate inserts, upserts, and updates to collections. A publication is none of those - it's readonly. Your use of SimpleSchema with .validate() inline would actually work but it's a pretty unusual pattern and a bit of overkill.
You might find this helpful.
CHECK is a lightweight package for argument checking and general pattern matching. where as SimpleSchema is a huge package with one of the check features. It is just that one package was made before the other.
Both works the same. You can use CHECK externally in Meteor.methods as well. Decision is all yours.
Michel Floyd answer's, made me realize that check() actually sends Meteor.Error(400, "Match Failed") to the client, while SimpleSchema within Methods sends detailed ValidationError one can act upon to display appropriate error messages on a form for instance.
So to answer the question : should we use check() or SimpleSchema() to assess our arguments types in Meteor, I believe the answer is :
Use SimpleSchema if you need a detailed report of the error from the client, otherwise check() is the way to go not to send back critical info.

Update document in Meteor mini-mongo without updating server collections

In Meteor, I got a collection that the client subscribes to. In some cases, instead of publishing the documents that exists in the collection on the server, I want to send down some bogus data. Now that's fine using the this.added function in the publish.
My problem is that I want to treat the bogus doc as if it were a real document, specifically this gets troublesome when I want to update it. For the real docs I run a RealDocs.update but when doing that on the bogus doc it fails since there is no representation of it on the server (and I'd like to keep it that way).
A collection API that allowed me to pass something like local = true this would be fantastic but I have no idea how difficult that would be to implement and I'm not to fond of modifying the core code.
Right now I'm stuck at either creating a BogusDocs = new Meteor.Collection(null) but that makes populating the Collection more difficult since I have to either hard code fixtures in the client code or use a method to get the data from the server and I have to make sure I call BogusDocs.update instead of RealDocs.update as soon as I'm dealing with bogus data.
Maybe I could actually insert the data on the server and make sure it's removed later, but the data really has nothing to do with the server side collection so I'd rather avoid that.
Any thoughts on how to approach this problem?
After some further investigation (the evented mind site) it turns out that one can modify the local collection without making calls to the server. This is done by running the same methods as you usually would, but on MyCollection._collection instead of just on Collection. MyCollection.update() would thus become MyCollection._collection.update(). So, using a simple wrapper one can pass in the usual arguments to a update call to update the collection as usual (which will try to call the server which in turn will trigger your allow/deny rules) or we can add 'local' as the last argument to only perform the update in the client collection. Something like this should do it.
DocsUpdateWrapper = function() {
var lastIndex = arguments.length -1;
if (arguments[lastIndex] === 'local') {
Docs._collection.update(arguments.slice(0, lastIndex);
} else {
Docs.update(arguments)
}
}
(This could of course be extended to a DocsWrapper that allows for insertion and removals too.)(Didnt try this function yet but it should serve well as an example.)
The biggest benefit of this is imo that we can use the exact same calls to retrieve documents from the local collection, regardless of if they are local or living on the server too. By adding a simple boolean to the doc we can keep track of which documents are only local and which are not (An improved DocsWrapper could check for that bool so we could even omit passing the 'local' argument.) so we know how to update them.
There are some people working on local storage in the browser
https://github.com/awwx/meteor-browser-store
You might be able to adapt some of their ideas to provide "fake" documents.
I would use the transform feature on the collection to make an object that knows what to do with itself (on client). Give it the corruct update method (real/bogus), then call .update rather than a general one.
You can put the code from this.added into the transform process.
You can also set up a local minimongo collection. Insert on callback
#FoundAgents = new Meteor.Collection(null, Agent.transformData )
FoundAgents.remove({})
Meteor.call 'Get_agentsCloseToOffer', me, ping, (err, data) ->
if err
console.log JSON.stringify err,null,2
else
_.each data, (item) ->
FoundAgents.insert item
Maybe this interesting for you as well, I created two examples with native Meteor Local Collections at meteorpad. The first pad shows an example with plain reactive recordset: Sample_Publish_to_Local-Collection. The second will use the collection .observe method to listen to data: Collection.observe().

Meteor is not transforming my documents before publication

For security reasons, I want to add and remove properties of documents before publishing them to the client, depending on some dynamic calculations. I follow the Meteor documentation and this other SO question.
For example simplicity, say I try to add the following static property to every document (SERVER SIDE ONLY):
var Docs = new Meteor.Collection('docs', {
transform: function (f) {
console.log('Tagging doc: ' + f._id);
f.myProp = 1;
return f;
}
});
For some strange reason, this does not work:
Only some documents trigger the transform function, not all (I can see this through the console logging)
On the client side, none of the documents are tagged with myProp
I haven't tried to put the transform on both the client and the server, because in my real life app I cannot do the necessary computation on the client.
Transform functions on collections are intended for convenience, not security -- note that when you call observeChanges on a cursor, the information is not passed through the transform function (it is passed through the transform when you call observe). The default way of publishing a cursor works by calling observeChanges on it.
If you want to strip off fields of a cursor you're publishing, use the fields option to find on your collection. If you want to do something more complicated, you can explicitly do whatever computation you need if your publish function calls added, changed, and removed itself, instead of returning a cursor. Check out the docs for Meteor.publish for details.

What's the difference between _isEnabled and isEnabled in Anguilla?

I've been following GUI extensions and notice examples use either _isEnabled or isEnabled, without the underscore. Both seem to work to extend or possibly replace existing functionality.
isEnabled
For example, the PowerTools base class (which doesn't seem to "extend" existing functionality) has:
PowerTools.BaseCommand.prototype.isEnabled = function(selection, pipeline)
{
var p = this.properties;
if (!p.initialized)
{
this.initialize();
}
if (!this.isToolConfigured())
{
return false;
}
if (this.isValidSelection)
{
return this.isValidSelection(selection, pipeline);
}
return true;
};
A tool can use this base class and declare .isValidSelection, for example:
PowerTools.Commands.CountItems.prototype.isValidSelection =
function (selection) { ... }
_isEnabled
I see Anguilla uses ._isEnabled for existing functionality (in Chrome's console in numerous places in the code). For example, WhereUsed has:
Tridion.Cme.Commands.WhereUsed.prototype._isAvailable =
function WhereUsed$_isAvailable(selection) ...
Private functions?
I'm familiar with a preceding underscore being a naming convention for private variables. Are the _isEnabled and other functions that start with an underscore "private?" If so, then
How should we extend (add additional functionality to existing code) these functions?
How should we replace (not have existing code run, but have ours run instead as in an "override") these?
I'm assuming the same approach applies to other functions that start with an underscore such as _isAvailable, and _invoke.
The following methods are called for a command:
isAvailable
isEnabled
invoke
The base class for all commands - Tridion.Core.Command - has a standard implementation of these methods. For the most part, this default implementation allows for extensions to Commands. They also call the underscore methods (_isAvailable, _isEnabled, and _execute).
I don't know why the CME commands only overwrite the underscore methods. Maybe someone thought it was just easier that way. They should be consider private (or the equivalent of "protected" in C#), so it actually seems like a bad practice to me.
It would be cleaner to implement the proper methods (isAvailable, isEnabled, and invoke) and then call the base implementation using this.callBase. However, you might need to stop the pipeline in this case, or also overwrite the underscore methods, in order to avoid your return value getting overwritten by the default underscore methods. It depends on the command you are implementing or extending.
In short: using the underscore methods is probably bad practice, but the Core implementation does seem to make it harder for you to do it "right". So I'd aim to avoid the underscore methods, but not sweat it if it turns out to be too hard to do so.
P.S. isValidSelection is a PowerTools-only method which separates the common logic that they all need from the logic specific to each command.

Resources