Closed (fixed)
Project:
Profile2 Registration Path
Version:
7.x-1.x-dev
Component:
Code
Priority:
Major
Category:
Support request
Assigned:
Unassigned
Reporter:
Created:
5 Apr 2011 at 21:32 UTC
Updated:
11 Oct 2012 at 02:47 UTC
I need to add ajax effects to my registration form created in profile2. I added #ajax, and wrote my callback function, but it isn't working properly. Which specific element in the array do I need to target in the wrapper, and which one do I return in the callback? Where can I read documentation on how different element types are assembled in the form array, and is this defined in profile2 or is it the entity api?
Comments
Comment #1
alexverb commentedI'm interested in the same thing. Seems like the ajax callback is not receiving the profile's $form variables, but only the registrations $form variables. So it can't return the form element from the profile that is targeted by ajax. This is odd behaviour. I have absolutly no clue how to fix this. On the profile's form on itself everything works as it should...
I think the key lies within function "profile2_attach_form" which is called from within function "profile2_form_user_register_form_alter".
Need support!
Comment #2
alexverb commentedSwitching this to a bug report for Drupal core. I narrowed it down to field_attach_form(). Any ajaxed form attached to the registration form can't return the required form element. I don't know if it's a field or ajax issue.
Comment #3
xjmSome clear steps to reproduce would be helpful here, preferably using just Drupal core.
Comment #4
alexverb commentedI couldn't reproduce using core alone. It's just working fine. I'm so sorry for creating a ghost bug! It's not even a Profile2 issue because that's working fine also.
I'm only getting this behaviour with Profile2 Registration Path. So for now I'm changing it back to a support request with that module. And I'm gonna dig into the code for a while...
Again my appologies...
Comment #5
alexverb commentedHow to recreate the bug:
The bug only seems to appear when "Show on all user account registration forms" is disabled. That checkbox ($profile_type->data['registration']) is used in the Profile2 module in the following function.
I dont really understand whats missing in $form_state['profiles'] by unchecking that checkbox that's causing the Ajax to fail. Maybe the maintainers from Profile2 and Profile2 Registration Path can help me out here? I'm about to go insane :)
Comment #6
grasmash commentedMywebmaster,
I will look into this issue today. I'll try to fix it soon, If it turns out to be a hard bug to squash, I may have to wait until after New Years to address it.
Comment #7
grasmash commentedHm... this is definitely strange. It seems like you can circumvent the bug by creating a blank profile type (no fields) and checking 'Show on all user account registration forms.' So, adding any profile type to all registration forms fixes it. Weird.
I'll continue to look into this.
Comment #8
grasmash commentedA couple of notes that could help lead to the answer:
Notice: Undefined index: #ajax in ajax_form_callback() (line 383 of /home/quickstart/websites/drupal7kit.dev/includes/ajax.inc).I'm out of time to work on this today. :(
Comment #9
alexverb commentedThx for looking into the issue so fast. I'll keep trying to look for a solution as wel. It seems Profile2 is not the only one suffering from this anomaly. Ctools form wizard as explained here http://drupalsteve.com/node/53 has reported a similar problem. I think it may be out of my league...
As I read that issue it looks like you can get around this problem by rerouting the ajax callback and doing a manual rebuild. But I thought the whole point of transforming AHAH (drupal 6) to AJAX (drupal 7) was to skip that step alltogether and simplify it for it's users.
If embedding or attaching a form means you still have to do it oldschool I don't see the benefits of using AJAX. That's why I still think it's more of a core issue then contrib...
Comment #10
grasmash commentedI agree. After researching similar issues, it seems like the root of the problem originates in the core AJAX system.
However, this works in profile2, so I feel that there must be a way to get it working with Profile2 Registration Path. Like you, I've stared at this code for quite a while, and I really can't identify any salient difference between the way that this module and Profile2 attach the profile fields—-they're nearly identical.
Comment #11
grasmash commentedTried essentially replacing profile2_regpath_form_user_registration_form_alter() with the function from profile2:
No change. I think that just about rules out profile2_regpath_form_user_register_form_alter() as the problem.
Comment #12
alexverb commentedI allready tried the same thing before:
If you hardcode (string) get_profile_type_by_path() to the actual string in your last piece of code every registration form receives the attached form. Same behaviour as the empty checkbox check...
It seems any if statement that returns TRUE will always add the form regardless of the url argument, as long as it is a registration form. Then again #AJAX works on all forms. Maybe we should just unset the unwanted forms LoL :)
Comment #13
grasmash commented#AJAX should work on all of the forms. Besides, profile2 is editing the registration form, and somehow it gets AJAX to work in an attached form. I just really don't see any difference in the approach between the two modules. Not making any sense to me...
For now, you can create a blank profile type, check 'show on all registration forms', and then unset it in a custom module.
E.g., create profile type 'bug_fix', check 'show on all registration forms', and add:
I hate it, but it's a bandaid.
Still need to figure out what's going on with the AJAX callbacks.
Comment #14
alexverb commentedI'm gonna go with that bandaid for a while because I'm all out of aspirin! Thx for sharing my annoyance with this bug. I'll jump back into it when my headache is gone ;)
Comment #15
grasmash commentedThat bandaid turns out to fail miserably for me :( Profile2 adds an additional submit handler to the form, which gets hung up on the missing form elements.
New thought:
Is it possible that my approach of adding an additional URL argument on the user registration page could somehow be disrupting AJAX's ability to send JSON back to the form?
This module currently grabs the value of % in 'user/register/%' and then attaches additional fields based on the profile that corresponds with that value. Could the presence of arg(2) somehow disrupt AJAX's functionality?
Would this be fixed if I actually registered the registrations path with Drupal's menu system?
It's really the only direction that I can think of at the moment. I'd love some input from anymore more familiar with Drupal AJAX!
Comment #16
grasmash commentedchanging version number.
Comment #17
grasmash commentedAfter a number of substantial changes, this bug has been fixed in the dev version. Primary changes include:
-creating a menu router item for each registration path (rather than using hook_form_alter)
-building the user registration form independently (rather than using hook_form_alter)
Let me know if you run into any more issues with this!
Comment #18
grasmash commentedEh. Nevermind, still not working!
Comment #19
grasmash commenteda bit more info from this issue:
http://drupal.org/node/1404458
Comment #20
grasmash commented@IronWorker from http://drupal.org/node/1117428
If I understand you correctly, you're saying that Drupal doesn't know which form to send AJAX requests back to because it uses get_profile_type_by_path() to identify the target form. However, this isn't correct. Drupal is actually using the form_id 'user_register_form' to identify the target form, which is derived from the usage of hook_form_FORM_ID_alter() in profile2_regpath_form_user_register_form_alter().
get_profile_type_by_path() is used to get the machine-name of the profile type to-be-attached. It then uses that machine-name in profile2_get_types() to load the profile object. That object is then passed into profile2_attach_form(), which attached it to the $form and $form_state objects that are passed by reference into hook_form_FORM_ID_alter().
This is the same way that the Profile2 module accomplishes attaching profile fields to the user registration form. It uses profile2_form_user_register_form_alter() to loop through every profile type and attach their fields to the registration form. The main difference between my approach and the one used in Profile2 is that I use get_profile_type_by_path() to specify which profile type should be attached, rather than looping through and adding all of them. Either way, the method of determining the correct $form, $form_state, and $form_id is the same.
But clearly, something is going wrong. You may be onto something and I may not have understood your analysis correctly.
Let me know your thoughts. Thanks!
Comment #21
IronWorker commentedwhat I'm noting is that get_profile_type_by_path() returns NULL from an AJAX request on a profile2 page that isn't attached to all of them ("Show on all user account registration forms" set off).
When this happens, the rest of the code doesn't match a profile2 page to attach, so it doesn't get attached.
I've noted that the profile *is* attached part way though the setup, but $form gets rebuilt in the middle of core in some cache context and it gets removed. The right stuff is in $form_state['profiles']['profilename'] but that isn't figured out because get_profile_type_by_path() returns NULL
Works fine when your profile 2 page has this "Show on all user account registration forms" set on.
Comment #22
IronWorker commentedI've got a profile that I call "instructor" so I get to it as user/register/instructor
When I get into the code loading the page, the code:
function get_profile_type_by_path() {
$profile_type = NULL;
$path = arg(2);
$profile_type = db_query("SELECT pt.type FROM {profile_type} pt LEFT JOIN {profile2_regpath} pr ON pt.id = pr.profile_id WHERE pr.path = :path AND pr.status = 1", array(':path' => $path))->fetchField();
return $profile_type;
}
$path is "instructor" as it should be. You get things loaded up correctly. arg() goes through and finds stuff as it has to and profile2_attach_form() gets called.
When I come into this with AJAX, you do go through profile2_form_validate_handler() which attaches the "profile_instructor" to $form, but that gets cleaned off in the rebuild of $form in drupal having to do with cache rebuilds. It then attempts to rebuild $form
eventually, we get to profile2_regpath_form_user_register_form_alter() which calls get_profile_type_by_path() first thing. $path at this time is NULL (arg(2) is attempting to parse system/ajax and, of course, cant find anything like a profile) and therefore $profiletype is FALSE which it returns and therefore profile2_attach_form() doesn't get called.
$form_state['values']['profile_instructor'] does exist but the equivalent $form structure never gets inserted.
profile2_form_user_register_form_alter() fires but it can't find any types it likes. and so goes theu the list of profiles without adding anything.
I'm using profile2 7.x-1.2 here....
I should also note that the dev version of this using by setup won't load unique profiles on special URLs at all. Basically, there is something about the regpath version of the form alter that is required to work.
Comment #23
grasmash commentedHm, I think I see what you mean. It makes sense that an AJAX request to the form wouldn't be able to find the correct arg().
I could temporarily store the value in $_SESSION, or perhaps in the drupal.settings json array. It's not sensitive information, so I don't really see the problem with that approach. I'll give it a shot.
Comment #24
grasmash commentedAlright, I *think* that I've solved the AJAX issue by storing the $profile_types information in $_SESSION and then accessing $_SESSION when a request is coming from 'system/ajax'
Seems to work, but I'd like some peer review on this. Somehow it doesn't feel like a best practice. Thoughts?
Comment #25
grasmash commentedmarking as fixed.
Comment #26
rfayI actually don't think you should have to do what you did. And I suspect field_attach_form() doing something evil when used with #ajax.
Comment #27
grasmash commentedIn that case, shouldn't you post an issue concerning this in the core queue? Just wondering why you re-activated the issue in this module... is it not working properly?
Comment #28
rfaySorry - looked like this had been to core and back. I suspect it's a legitimate issue.
I'm marking fixed then.
Comment #29
grasmash commentedThanks!
Did you happen to find or file an issue for this in core? If not, I will.
Comment #30
rfayI don't understand it well enough to file yet, but would very much appreciate a link to your issue.
Comment #31
alexverb commentedI think it's because field_attach_form() doesn't put the new combined form into cache. And since the ajax callback uses ajax_get_form() which retrieves the form from cache you end up with a form that hasn't got the other one attached.
Weird thing is when you make the ajax callback in the same module that alters and attaches the form there is no problem. Whenever you make the callback from another module that hasn't attached it itself, the ajax callback fails.
This might have something to do with that last piece of code in field_attach_form()
So it actually makes sence that only modules that invoke the field_attach_form are able to alter it. But then again profile2_attach_form() has code that makes the form_alter hook available to other modules. And it looks that on this end something is not working as it's supposed to.
So my thought is it's not a core bug. But I still can't wrap my head around this problem. Because of that I'm happy with the solution that madmatter23 has made. But as him I feel the solution is not the one that feels right. But it works and doesn't seem to have any performance issues...
Comment #33
debo7debo commentedCan someone create the patch for this please? I have this same problem right now but don't have a clue how to apply the fix by madmatter23 in comment #24.
Comment #34
grasmash commented@debo7debo this fix was applied over a year ago. If you are encountering a similar issue, please open a new issue and describe your exact situation.