Adding Elements To Collections and Reactivity - collections

What is the intended reactive behaviour when adding a document to a published collection? More specific: does adding a document to a collection invalidate all subscriptions to that collection (even those that are not matching) and result in a re-rendering of all dependent ui elements?
That's what I'm experiencing right now, at least.
To be even more specific: I have forms, with some "normal" fields but also lists. Those lists contain subforms which contain fields as well. Both types of forms are stored in a single generic Data collection. The view on this Data collection is managed with fine-grained subscriptions.
When I add a new list element, a new subform to the base form, the whole base form is re-rendered. Even none related base forms are re-rendered.
I have a github repo showing this, a little obfuscated though. It's a movie database. You can add a movie, give it a name, a tagline and add actors to the movie. An actor has a name and a home. When adding an actor to a movie every movie is re-rendered.
https://github.com/Crenshinibon/fields3/tree/462a9291bfc400a2731c21d2debdd4071be764ed
I'm aware of this question: Understanding Meteor Publish / Subscribe and think this part is actually missing. (I just don't have enough reputation points to ask in the comments) I understand the Pub/Sub mechanism of Meteor pretty well, I think. Just the resulting reactive behaviour is a little bit unclear.
I'm also aware of this question: Reactivity, isolation, and lists. But it's for Spark and Blaze changed a lot (especially, it made #isolate obsolete.)
And before I rebuild my app (again) to put all kinds of forms (or even properties) in different collections to avoid the "whole page" of being reloaded, I thought I might ask and maybe there is something I'm missing.
I'm on 0.9.0-rc10.

You should not put the subscribe calls in Meteor.autorun.
Meteor.autorun is a reactive context, meaning everything inside will get re-run if a reactive data source changes inside. We’re storing the channel we’re in inside the Session under "current_channel". If that session value changes, then the subscription is renewed and we have access to different messages!
src
Instead do something like this in your javascript:
Template.viewContent.movies = function () {
var subscription = Meteor.subscribe('movies');
return {
data: Movies.find(),
ready: subscription.ready
};
}
Then your template will look like this:
{{#each movies}}
{{#if ready}}
{{#each data}}
#DOSOMETHING WITH THE MOVIES#
{{/each}}
{{else}}
!!!Loading indicator here!!!
{{/if}}
{{/each}}

Related

How should I design a multiscreen feature?

I work on a webapp with a workspace, where the user can create, load, and edit documents. This workspace is built with several areas, each taking care of a part of the job. A set of document loaded in a workspace is called a "project" and is stored in a "project" collection.
The data involved in a project is of two types:
the set of documents attached to the project. It is stored in the mongo document in the "project" collection
the current document a specific user is working on. I do not store it yet, I just use a set of global reactive variables to load a document and the attached informations when a user click on it. It means every time a user access to the workspace/project, he will not find the previously loaded documents but no documents loaded at all.
I now want to store the second type of data with one major requirement: to allow the user to work in an "extended mode" where one of the panels is in a dedicated browser window (supposedly on another screen). It means that if he clicks on a document in a window, the document is loaded in the other window/screen.
As far as I know, I can't send information directly from one browser window to another. I have to use the server to relay the information. So the user clicks on a document > the new loaded document id is sent to the server > the other window update accordingly.
Is my assumption correct? (the server must relay the info)
To implement this feature, I figured out a couple of solutions:
I attach a "project" field to the user profile mongo document. In each of these fields, I will have the last items loaded for each project and I will use this field to update one screen from the other.
I create a specific field in each project document where, for each user who worked on the project, I store the currently loaded document and its settings.
The first option suppose to load every project information along with the user profile (i.e. in every page) and could lead to send many times useless informations.
The second option will trigger the meteor reactivity mechanisms each time a user loads an item (without actually modifying the project) for every user connected to the project.
Each option has serious downsides, and I would like to know which one seems to be the better to you and if you can think of other alternatives.
You ought to be able to use one of the reactive local storage packages for Meteor especially if you are not concerned about not supporting non-HTML5 browsers... Can't give a massive amount of guidance on what one having not used most of them but the HTML5 local storage is usable across tabs and seems like a good place to store your data without a round trip to the server whilst also allowing it to persist between tabs.
You could also roll your own implementation (may be simpler than trying to find a package to match your needs exactly) by adding a listener to the app for local storage setitem() and removeItem() events as per this helpful guide from which the below code has been shamelessly copied...
if (window.addEventListener) {
// Normal browsers
window.addEventListener("storage", handler, false);
} else {
// for IE (why make your life more difficult)
window.attachEvent("onstorage", handler);
};
function handler(e) {
console.log('Successfully communicate with other tab');
console.log('Received data: ' + localStorage.getItem('data'));
//Add in your code to display the document on the second tab
}
localStorage.setItem('data', 'hello world');

Meteor schemas autoform hooks has inconsistent values

I have two update forms, one for each of two collections, which have identical before update hooks.
before:{
update: function(docId, modifier, template){
console.log(arguments);
return modifier;
}
}
One gives me:
["eEWR4xqdZjdprKGN7", Object, Blaze.TemplateInstance]
Which is exactly what I expect and all is great.
The other gives me:
[Object, Blaze.TemplateInstance]
Object here has $set and $unset keys with corresponding Objects giving me the values I expect to see that I put in my form.
Beyond that... I'm using autosave with both forms. I'm not sure what other information to post. I have a LOT of code and pretty beefy schemas, and I don't know what would cause this or where to start.
The problem it's giving me is that I have a helper function registered to update the forms on their respective templates using Meteor's awesome reactive stuff, which isn't happening on the second form. But it works on the first.
Template.updatePerson.helpers({
getDocument: function(){
return people.find(this.person_id).fetch()[0];
}
});
Again, these two forms are nearly identical except for the schemas and names, but I've tried lots of adjusting to the second schema with no change.
Anyone who can tell me why those two arguments coming back are different would be greatly appreciated.
Ends up my helper on the second template wasn't properly pulling the document ID (looking for wrong key). The results I was seeing must have been from autoform not having access to a document for its update method.

Collection.findOne() does not return any results in Template.created

I have a template which is a simple edit form. The _id of the document to be edited comes in a session variable (set by mini-pages from the URL: http://example.com/items/4zt4z3t3t). In the Template.editForm.createdfunction I try to get the correponding document from the collection using ItemCollection.findOne({_id:_id}). The _id is set correctly in all cases.
When I navigate to http://example.com/4zt4z3t3t and debug the created function, ItemCollection.findOne()returns undefined, although there are items in the collection. Therefore I can never find my item by _id. Also, when I move the item find procedure to the routing stage, there is also no result for the find. Later on, the colleciton works as expected.
Any pointers?
Meteor uses a Data on the wire principle. This means when your HTML has loaded your data isn't sent along with it, at least initially.
You can't therefore access data in a .created function, unless you expect that template to be loaded after the data has been downloaded. This is why it returns undefined initially but if you check later its there.
You can either, wait for a callback from the subscription on when the data is completed, then load the template.
OR
Use reactivity in your template and let it load empty, and automatically fill it up with data when the data has come in (really the easiest). Access your data in the template and use a handlebars helper to fill in the data and use the .rendered callback to do any changes after.

Flex-Cairngorm/Hibernate - Is EAGER fetching strategy pointless?

I will try to be as concise as possible. I'm using Flex/Hibernate technologies for my app. I also use Cairngorm micro-architecture for Flex. Because i'm beginner, i have probably misunderstand something about Caringorm's ModelLocator purpose. I have following problem...
Suppose that we have next data model:
USER ----------------> TOPIC -------------> COMMENT
1 M 1 M
User can start many topics, topics can have many comments etc. It is pretty simple model, just for example. In hibernate, i use EAGER fetching strategy for unidirectional USER->TOPIC and TOPIC->COMMENT relations(here is no question about best practices etc, this is just example of problem).
My ModelLocator looks like this:
...
public class ModelLocator ....
{
//private instance, private constructor, getInstance() etc...
...
//app state
public var users:ArrayCollection;
public var selectedUser:UserVO;
public var selectedTopic:TopicVO;
}
Because i use eager fetching, i can 'walk' through all object graph on my Flex client without hitting the database. This is ok as long as i don't need to insert, update, or delete some of the domain instances. But when that comes, problems with synchronization arise.
For example, if i want to show details about some user from some UserListView, when user(actor) select that user in list, i will take selected index in UserList, get element from users ArrayCollection in ModelLocator at selected index and show details about selected user.
When i want to insert new User, ok, I will save that user in database and in IResponder result method i will add that user in ModelLocator.users ArrayCollection.
But, when i want to add new topic for some user, if i still want to use convenience of EAGER fetching, i need to reload user list again... And to add topic to selected user... And if user is in some other location(indirectly), i need to insert topic there also.
Update is even worst. In that case i need to write even some logic...
My question: is this good way of using ModelLocator in Cairngorm? It seems to me that, because of mentioned, EAGER fetching is somehow pointless. In case of using EAGER fetching, synchronization on Flex client can become big problem. Should I always hit database in order to manipulate with my domain model?
EDIT:
It seems that i didn't make myself clear enough. Excuse me for that.
Ok, i use Spring in technology stack also and DTO(DVO) pattern with flex/spring (de)serializer, but i just wanted to stay out of that because i'm trying to point out how do you stay synchronized with database state in your flex app. I don't even mention multi-user scenario and poling/pushing topic which is, maybe, my solution because i use standard request-response mechanism. I didn't provide some concrete code, because this seems conceptual problem for me, and i use standard Cairngorm terms in order to explain pseudo-names which i use for class names, var names etc.
I'll try to 'simplify' again: you have flex client for administration of above mentioned domain(CRUD for each of domain classes), you have ListOfUsersView(shows list of users with basic infos about them), UserDetailsView(shows user details and list of user topics with delete option for each of topic), InsertNewUserTopicView(form to insert new topic) etc.
Each of view which displays some infos is synchronized with ModelLocator state variables, for example:
ListOfUsersView ------binded to------> users:ArrayCollection in ModelLocator
UserDetailsView ------binded to------> selectedUser:UserVO in ModelLocator
etc.
View state transition look like this:
ListOfUsersView----detailsClick---->UserDetailsView---insertTopic--->InsertTopicView
So when i click on "Details" button in ListOfUsersView, in my logic, i get index of selected row in ListOfUsers, after that i take UserVO object from users:ArrayCollection in ModelLocator at mentioned index, after that i set that UserVO object as selectedUser:UserVO in ModelLocator and after that i change view state to UserDetailsView(it shows user details and selectedUser.topics) which is synchronized with selectedUser:UserVO in ModelLocator.
Now, i click "Insert new topic" button on UserDetailsView which results in InsertTopicView form. I enter some data, click "Save topic"(after successful save, UserDetailsView is shown again) and problem arise.
Because of my EAGER-ly fetched objects, i didn't hit the database in mentioned transitions and because of that there are two places for which i need to be concerned when insert new topic for selected user: one is instance of selectedUser object in users:ArrayCollection (because my logic select users from that collection and shows them in UserDetailsView), and second is selectedUser:UserVO(in order to sync UserDetailsView which comes after successfull save operation).
So, again my question arises... Should i hit database in every transition, should i reload users:ArrayCollection and selectedUser:UserVO after save in order to synchronize database state with flex client, should i take saved topic and on client side, without hitting the database, programmatically pass all places which i need to update or...?
It seems to me that EAGER-ly fetched object with their associations is not good idea. Am i wrong?
Or, to 'simplify' :) again, what should you do in the mentioned scenario? So, you need to handle click on "Save topic" button, and now what...?
Again, i really try to explain this as plastic as possible because i'm confused with this. So, please forgive me for my long post.
From my point of view the point isn't in fetching mode itself but in client/server interaction. From my previous experience with it I've finally found some disadvantages of using pure domain objects (especially with eager fetching) for client/server interaction:
You have to pass all the child collections maybe without necessity to use them on a client side. In your case it is very likely you'll display topics and comments not for all users you get from server. The most like situation you need to display user list then display topics for one of the selected users and then comments for one of the selected topics. But in current implementation you receive all the topics and comments even if they are not needed to display. It is very possible you'll receive all your DB in a single query.
Another problem is it can be very insecure to get all the user data (or some other data) with all fields (emails, addresses, passwords, credit card numbers etc).
I think there can be other reasons not to use pure domain objects especially with eager fetching.
I suggest you to introduce some Mapper (or Assembler) layer to convert your domain objects to Data Transfer Objects aka DTO. So every query to your service layer will receive data from your DAO or Active Record and then convert it to corresponding DTO using corresponding Mapper. So you can get user list without private data and query some additional user details with a separate query.
On a client side you can use these DTOs directly or convert them into client domain objects. You can do it in your Cairngorm responders.
This way you can avoid a lot of your client side problems which you described.
For a Mapper layer you can use Dozer library or create your own lightweight mappers.
Hope this helps!
EDIT
What about your details I'd prefer to get user list with necessary displayable fields like first name and last name (to display in list). Say a list of SimpleUserRepresentationDTO.
Then if user requests user details for editing you request UserDetailsDTO for that user and fill tour selectedUser fields in model with it. The same is for topics.
The only problem is displaying list of users after user details editing. You can:
Request the whole list again. The advantage is you can display changes performed by other users. But if the list is too long it can be very ineffective to query all the users each time even if they are SimpleUserRepresentationDTO with minimal data.
When you get success from server on user details saving you can find corresponding user in model's user list and replace changed details there.
Tell you the truth, there's no good way of using Cairngorm. It's a crap framework.
I'm not too sure exactly what you mean by eager fetching (or what exactly is your problem), but whatever it is, it's still a request/response kind of deal and this shouldn't be a problem per say unless you're not doing something right; in which case I can't see your code.
As for frameworks, I recommend you look at RobotLegs or Parsley.
Look at the "dpHibernate" project. It implements "lazy loading" on the Flex client.

Grails - Removing an item from a hasMany association List on data bind?

Grails offers the ability to automatically create and bind domain objects to a hasMany List, as described in the grails user guide.
So, for example, if my domain object "Author" has a List of many "Book" objects, I could create and bind these using the following markup (from the user guide):
<g:textField name="books[0].title" value="the Stand" />
<g:textField name="books[1].title" value="the Shining" />
<g:textField name="books[2].title" value="Red Madder" />
In this case, if any of the books specified don't already exist, Grails will create them and set their titles appropriately. If there are already books in the specified indices, their titles will be updated and they will be saved. My question is: is there some easy way to tell Grails to remove one of those books from the 'books' association on data bind?
The most obvious way to do this would be to omit the form element that corresponds to the domain instance you want to delete; unfortunately, this does not work, as per the user guide:
Then Grails will automatically create
a new instance for you at the defined
position. If you "skipped" a few
elements in the middle ... Then Grails
will automatically create instances in
between.
I realize that a specific solution could be engineered as part of a command object, or as part of a particular controller- however, the need for this functionality appears repeatedly throughout my application, across multiple domain objects and for associations of many different types of objects. A general solution, therefore, would be ideal. Does anyone know if there is something like this included in Grails?
removeFrom*
Opposite of the addTo method in that it removes instances from an association.
Examples
def author = Author.findByName("Stephen King")
def book = author.books.find { it.title = 'The Stand' }
author.removeFromBooks(book)
Just ran into this issue myself. It's easy to solve. Grails uses java.util.Set to represent lists. You can just use the clear() method to wipe the data, and then add in the ones you want.
//clear all documents
bidRequest.documents.clear()
//add the selected ones back
params.documentId.each() {
def Document document = Document.get(it)
bidRequest.documents.add(document)
log.debug("in associateDocuments: added " + document)
};
//try to save the changes
if (!bidRequest.save(flush: true)) {
return error()
} else {
flash.message = "Successfully associated documents"
}
I bet you can do the same thing by using the "remove()" method in the case that you don't want to "clear()" all the data.
For a good explanation of deleting a collection of child objects with GORM have a look at the Deleting Children section of this blog post - GORM gotchas part 2
It's recommended reading, as are parts 1 and 3 of the series.
I am just starting to learn Grails myself and saw your question as an interesting research exercise for me. I do not think you can use the conventional data binding mechanism - as it fills in the blanks using some kind of Lazy map behind the scenes. So for you to achieve your goal your "save" method (or is it a function?) is unlikely to contain anything like:
def Book = new Book(params)
You need a mechanism to modify your controller's "save" method.
After some research, I understand you can modify your scaffolding template which is responsible for generating your controller code or runtime methods. You can get a copy of all the templates used by Grails by running "grails install-templates" and the template file you would need to modify is called "Controller.groovy".
So in theory, you could modify the "save" method for your whole application this way.
Great! You would think that all you need to do now is modify your save method in the template so that it iterates through the object entries (e.g. books) in the params map, saving and deleting as you go.
However, I think your required solution could still be quite problematic to achieve. My instinct tells me that there are many reasons why the mechanism you suggest is a bad idea.
For one reason, off the top of my head, imagine you had a paginated list of books. Could that mean your "save" could delete the entire database table except the currently visible page? Okay, let us say you manage to work out how many items are displayed on each page, what if the list was sorted so it was no longer in numerical order - what do you delete now?
Maybe multiple submit buttons in your form would be a better approach (e.g. save changes, add, delete). I have not tried this kind of thing in Grails but understand actionSubmit should help you achieve multiple submit buttons. I certainly used to do this kind of thing in Struts!
HTH
I'm just running into this same issue.
My application's domain is quite simple: it has Stub objects which have a hasMany relationship with Header objects. Since the Header objects have no life of their own, they're entirely managed by the Stub controller and views.
The domain class definitions:
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {headers lazy: false}
}
class Header {
String value
static belongsTo = Stub
}
I've tried the "clear and bind" method but the end result is that the "cleared" objects are left over in the database and grails will just create new instances for the ones that were not removed from the relationship. It does seem to work from an user's perspective, but it will leave lots of garbage objects in the database.
The code in the controller's update() method is:
stubInstance.headers.clear()
stubInstance.properties = params
An example: while editing the -many side of this relationship I have (for a given Stub with id=1):
<g:textField name="headers[0].value" value="zero" id=1 />
<g:textField name="headers[1].value" value="one" id=2 />
<g:textField name="headers[2].value" value="two" id=3 />
in the database there are 3 Header instances:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
after removing header "one" and saving the Stub object the database will have headers:
id=1;value="zero"
id=2;value="one"
id=3;value"two"
id=4;value="zero"
id=5;value="two"
and the Stub object will now have an association with Headers with id=4 and id=5...
Furthermore, without the clearing of the list, if an index is not present in the submitted request.headers list, on data binding grails will keep the existing object at that location unchanged.
The solution that occurs to me is to bind the data, then check the Stub's headers for elements that are not present in the submitted list and remove them.
This looks like a pretty simple scenario, isn't there any built-in functionality to address it?
It's a bit overkill to have to write your own synchronization logic for maintaining relationships, especially when the quirks that make it non-trivial are caused by grails itself.
What about deletion, shouldn't the clear()'ed elements be gone from the database? Am I missing something in the relationship or domain object definitions?
class Stub {
List headers = new ArrayList();
static hasMany = [headers:Header]
static mapping = {
headers lazy: false
**headers cascade: "all-delete-orphan"**
}
}
class Header {
String value
static belongsTo = Stub
}
I have added the cascade property on the owning side of relationship and Now if you try to save the stub, it will take care of removing deleted items from the collection and delete them from the DataBase.

Resources