dominar
dominar copied to clipboard
Removing controls from DOM after Dominar has been initialized
The framework I'm using (Meteor) can remove controls after Dominar has been told about them. Not hide them, but take them out of the DOM. I believe Angular and React do the same.
Dominar::validateAll is not happy about fields not being there.
I hacked in a
if(!field)
continue
inside the for loop and everything appears to be working fine. Am I asking for trouble doing this?
I should probably add a removeField
and general destroy
function to dominar, along with a general config option for ignoreMissingFields
? What do you recon?
Those would be great. All of my views/templates (html fragments) have created, rendered and destroyed events (part of the framework) so being able to cleanly remove Dominar when the template is removed would be great.
Also, single page frameworks like Meteor and Angular NEVER do Form submissions: data maybe collected from forms or controls (very common for there to be no Form at all, just groups of controls, Dominar seems fine with this as long as the Selector is in the DOM when the validator is created), The control data is sent to the backend through api's built into the framework, Meteor relying solely on sockets and angular having its own restful api as well as socket framework. The classic form submittal just doesn't happen.
So, I have to include
$('#someDomId').bind('dominar.submit-passed', function(event) {
event.preventDefault();
});
in every template, to keep Dominar from sending off the form data. It would be nice to be able to set an option like submit: false
and be able to eliminate the need to repeat this code in every template.
I mention this last one as I was getting very unpleasant results testing a template ... caused by a 'copy and paste' error where I didn't change the selector for the bind.
Just added a destroy
method to dominar. Does that help with Meteor?
I was going to pull down the latest when I noticed that the dist folder hasn't been updated?! I've been using dominar-standalone.js.... The destroy will obviously free up memory (which is always a good thing).... what I need to not keep using my hacked Dominar is for Dominar to be ok with controls being removed underneath it (see my comment at the top of this thread)
Yeah I haven't released new version yet. I'm going to hold off until I get a chance to release validatorjs 2.0.
I was thinking when you remove the elements (or meteor) why not just re-initialize dominar on the form, would that not work for you?
It just gets complicated quickly. The markup looks like
{{#if thisBeTrue}}
// markup here
{{/if}}
where thisBeTrue is a 'reactive' function that will be called if anything inside it changes. There can be many of these on a page and they can be nested, when exactly the DOM is ready is a guess so I was hacking in setTimeouts to be able to call validateAll() and be certain Meteor had 'really' rendered the controls. I found (and it's working) it to be much simpler to initialize all the controls you will be needing (or possibly needing) in a single event (onRendered) and just 'help' Dominar with the little hack above.
As i mentioned this is not peculiar to Meteor, Angular and React do the same thing.
I'm definitely interested in supporting, just need to find a decent way of doing it. :smile:
When the view is rendered in Meteor onRendered
could you .destroy
and then re-initialize with the newly rendered view? I haven't any understanding of Angular / Meteor / React but I am fairly confident that they will produce some form of events that can be used to know when to re-initialize dominar on the form. That will free up any existing initialized fields, events, etc.
This is pretty common in a lot of plugins like date pickers, custom selects / checkboxes, etc. You need to reinitialize them once the view changes, I don't see why it would be much different from Dominar.
Just to be clear: I'm talking about 'Blaze' Meteor's original renderer. Any day now there will be a new release of Meteor. Both React and Angular will be able to coexist with or replace Blaze. I'm very familiar with Angular (it has its own validation framework) and know little about React (it does not have a validation framework). If for no other reason than Facebook's muscle, React is and will be a big player in Meteor.
The problem with OnRendered is that it is only called once and it only tells you that the template has been rendered, it doesn't tell you if 'markup here' (see above) has been rendered. The markup (controls) may be created or destroyed by any number of 'events'. This is what makes Meteor so popular:
The thisBeTrue function above could be as simple as return col.someProp === true;
Where col.someProp is a remote database property. If someProp changes in the database (doesn't have to be my app that changes it) controls will appear or disappear in my UI. Even if you try and keep track of the state yourself, you may be an 'event loop' behind and the controls haven't yet been put in the DOM and your call to validateAll will fail. So I either ended up hacking Dominar or putting in setTimeouts
How does Meteor recommend to handle initializing e.g. date pickers, custom selects, star ratings, wysiwyg editors, sortable elements, etc when the view is constantly being re-rendered / changed with new elements? There must be a way it recommends when you should rebind stuff. I'm still not sure what the actual problem is with .destroy
and re-initializing?
I suspect (but I'm on thin ice here as I know very little about React) that Reacts popularity in the Meteor community has to do with this very issue at least in part. Your example of the datePicker is good. If its in its own child template it will get events for being created and destroyed ... but now you have a Dominar with controls spread across multiple templates, which I don't want to even think about. Just to be clear: Meteor only rerenders what you tell it to. You can just 'hide' elements the old fashion way. I do have complete groups of controls that are added and removed. The rest of the form is not rerendered. Dominar validateAll works fine (controls missing) with the small 'fix' above.
What I'm trying to suggest is when you know your view has been re-rendered (thru 'done rendered' events, or whatever) THEN do dominar.destroy()
and var dominar = new Dominar(..., ...);
that way it will clear the whole instance and re-attach the events that it needs, etc. That would fix the submit issue.
Your not really answering the question if the above will work (sorry I don't know Meteor at all, but in all frameworks I've used you need to re-initialize stuff at some point exactly as I described above). Have you tried the new code for dominar with .destroy and see if it works?
I think we are talking about different things here: There is no re-render event. Just a single rendered event There is no render event for this markup
{{#if thisBeTrue}}
// show these controls
{{/if}}
'show these controls' may come and go. No events are fired when these controls are added or removed from the DOM. 'thisBeTrue' is called by Meteor every time something inside the function changes (this is the 'magic' of Meteor). The template that contains this markup will fire an onRendered one time when it is first added to the DOM. This does NOT tell me if the 'show these controls' are present (were rendered).
So, yes I am doing new Dominar in the onRendered event. But I can't know which controls I'll need so I give Dominar all that can possibly appear.
As to your question 'How does Meteor recommend..' Meteor is still the Wild West .... hopefully it will settle down this year ...
In all honesty, I think that's a pretty stupid design by Meteor. How come you can't tell when a control is updated? I really don't see how on earth you can confidently know when you should re-initialize date pickers, etc when it doesn't fire any form of event, so this problem isn't specific to dominar. Maybe you could take it up with them about why no events are fired when the UI is updated? How do they recommend to reinitialize stuff etc.
I think the answer in the Meteor community has been React and Angular ... and I assume that the to-be- -released-any-minute-now update to Meteor with core support for different rendering engines confirms it. Blaze ain't going away, very easy to use, just gets difficult with component based UI's. Just to be clear: Meteor doesn't 'event' the control being updated ... I could set my own 'global' in 'thisBeTrue' which would function as an event. Its ugly as I mentioned because it just means the controls will be shown not that they are there now (event loop woes)
I'm working with a highly dynamic form, without a framework like Meteor, React and Angular and I've added the following to help with debugging.
if (!field) {
throw new ReferenceError(name);
}
I think we need a by field destroy method.
Just trying to think of the best way to fix this. It is easy to add a way of skipping the fields that are missing, but I think there is some value in knowing when you've added validation to a field that is required
and the field doesn't even exist in the DOM (a developer issue, but it will fail silently which isn't particularly nice).
Also simply skipping the missing fields and having one monolithic instance of dominar throughout the life of the app might get sluggish over time (I believe that's how @stocksp is using it?).
Would there be any considerations to automatically removing the field from dominar when it comes across a missing field in validateAll()
? Kind of like a self cleanup option.
I also toyed with an idea of a missingField
option which will determine what dominar should do once it stumbles across a missing field. This would only be used in validateAll()
-- doing .getField('blahh missing field').validate()
will always error regardless.
missingField: 'ignore'
missingField: 'cleanup'
missingField: 'error'
I like the missingField option or maybe an environment
option with some defined behaviours.
environment: 'dev' | 'test' | 'live'
dev
would throw
test
would console.error()
live
could cleanup or ignore, whichever is safest.
Not too keen on the environment option, I think that's probably a bit too
complicated. If you needed specific settings for an environment make a
wrapper in your app something like var dominar = new Dominar($('form'), buildDominarSettings('dev', { ... }));
I'm correct in thinking it's only .validateAll your having the problem with?
On 1 October 2015 at 12:42, Richard Ayotte [email protected] wrote:
I like the missingField option or maybe an environment option with some defined behaviours.
environment: 'dev' | 'test' | 'live'
dev would throw test would console.error() live could cleanup or ignore, whichever is safest.
— Reply to this email directly or view it on GitHub https://github.com/garygreen/dominar/issues/17#issuecomment-144704175.
Yes, .validateAll
is the culprit.