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.
Related
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}}
I'm new to the Meteor framework, and am having problems accessing data from my collection, outside of a template.
I have a small mongo collection and can retrieve and present its data without problems by using a template. However, when I try to get a cursor or array to use more directly, I get no results returned.
In my script, using find
var dataFind = Fakedata.find();
console.log(dataFind);
console.log(dataFind.count());
gives a cursor object, but a count of zero.
var dataFetch = Fakedata.find().fetch();
console.log(dataFetch);
console.log(dataFetch.length);
gives an empty array, length of zero.
Using the same find() or fetch() from the JS console gives populated objects as I would expect the code above to do. Within a meteor template, everything seems to work fine as well, so the pub/sub seems to be correct.
Any clues as to what I'm doing wrong here?
It looks like your subscriptions aren't ready at the time you try to access your collection data, this is a common gotcha.
When you access your collection data via templates, it is most likely via the use of template helpers which happen to be reactive, so they will rerun when your collections are ready thus displaying the correct data.
When accessing your collections in a non-reactive script though, they will appear empty if the subscription is not yet ready.
You can try using this pattern in your script to execute code only when the subscription is ready :
Meteor.subscribe("mySubscription",function(){
// we are inside the ready callback here so collection date is available
console.log(Fakedata.find().fetch());
});
If you are looking for a more robust approach, try looking at iron:router waitOn mechanism.
After creating a model and adding it to a repository I want to have the new ID for different purposes (creating a mail, updating other fields outside the Extbase world)
$page = t3lib_div::makeInstance('Tx_MyExt_Domain_Model_Page');
$page->setTitle('Hello World');
$this->pageRepository->add($page);
At this point $page hasn't got an ID yet, uid is null.
$page->getUid(); // returns null
When does it get it? And how can I retrieve in on runtime?
In ExtBase, objects are "managed". This means every persistence transaction (add/remove/update) is simply noted in the underlying logic, but not yet executed until the appropriate time (like the end of processing a request). So, just because you add an object to a repository doesn't mean that it's actually added yet. That actually happens once $persistenceManager->persistAll() is called, which isn't something you need to do manually, ever. The point is, your $page object won't have a UID until it's saved and that's why $page->getUid() returns null. Look here for a great explanation.
I suspect that you are trying to do something outside of the ExtBase object/MVC lifecycle. At least, last time I got null when I tried to get the UID of an object, it was because I wasn't operating within the framework appropriately.
However, if you post some more code and give us a bigger picture of what you're trying to achieve, maybe we can help you get to a point where that object actually has a UID. For instance, if you're in a Controller object, tell us which Action method you're in, or if you're in a Repository object, tell us what you're trying to get from the repository and where/how you plan on using the query results.
EDIT
Just guessing here, but I'm assuming you're executing this code in some action of a controller. Since after the controller is executed a view is rendered, you can just pass the page object to the view:
$this->view->assign('page', $page);
And then in your view you can use the page object in a link:
<f:link.action action="show" arguments="{page:page}">
See this page object
</f:link.action>
And then in the show action of your controller you can show the page:
public function showAction(Tx_MyExt_Domain_Model_Page $page) {
// Do whatever you need to show the page in the `Show.html` template
}
I really am just guessing here. If you can give us a larger picture of what you're trying to do, what your action methods are supposed to do and things like that, we can answer your question a little more confidently.
(I'm also assuming that your page object isn't a replacement for the regular TYPO3 pages and that they are something totally different. It's much easier to deal with those TYPO3 pages through the backend interface than at the php level.)
You can call persistence manager explicitly in Your controller like this
#TYPO3 4.x
$persistenceManager = $this->objectManager->create('Tx_Extbase_Persistence_Manager');
$persistenceManager->persistAll();
#TYPO3 6.x
$persistenceManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager');
$persistenceManager->persistAll();
I have a custom user control (ascx) that contains a textbox and a Javascript-based counter to let the user know many characters they have left to type. In this control is the following:
function GetTextBox() {
return document.getElementById("<%=txNotes.ClientID %>");
}
This worked fine when we only had one instance of this user control on the page, but now we have to support multiple. As you know, having multiple instances of this control on a page will result in multiple GetTextBox() functions, only the last of which will be called no matter what. To support multiple instances, I use this:
if (!string.IsNullOrEmpty(TextBoxName) && !Page.ClientScript.IsClientScriptBlockRegistered(TextBoxName))
{
string Script = string.Format("function Get{0}Notes() {{ return document.getElementById(\"{1}\"); }}",
TextBoxName, txNotes.ClientID);
Page.ClientScript.RegisterClientScriptBlock(GetType(), TextBoxName, Script, true);
}
TextBoxName is a public usercontrol property, so if the developer passes Employee through, it will generate a Javascript function called GetEmployeeNotes(). This works greate because now we can have a unique GetNotes() function.
However, I don't like how it's hardcoded into the codebehind. I would like a markup-based solution for this, something that doesn't require a rebuild of the project in case I want to change the Javascript. Does anyone know of a way to do this?
Edit: I've already thought of creating a separate .js file that I could read with a text reader, but that sounds a bit hacky and I'd like to avoid that if at all possible.
Edit 2: Guard's answer below would work, but I don't want to go that route for the reason I gave beneath his answer. If no one can offer another way to do what I want to do, I will most likely mark his as the answer since it technically does exactly what I am asking.
I'm not a .NET specialist, but isn't it working as a preprocessor?
Isn't it legal to write
function Get<%=Name %>Notes() {...}
?
Why not use a generic function and just pass the id of the corresponding textbox? As in: GetNotes(thisTextBoxId) {...}. Not only would that deal with your problem but also is more DRY.
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.