1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Form Submitted From Within An Overlay

Discussion in 'XenForo Development Discussions' started by digitalpoint, Feb 5, 2012.

  1. digitalpoint

    digitalpoint Well-Known Member

    I have an overlay that pops up that allows the user to enter some things and it's working. I'm using data-redirect="on", and the controller is returning message when it's submitted just fine...

    PHP:
    return $this->responseMessage('Message to user');
    Like it would be nice if there was a controller response type along the lines of:

    PHP:
    [php]return $this->responseJavascript($JsCode'Optional Message to user'$redirect == false);
    But what I would *like* to do is not have to reload the page upon submission, and instead just fire some JavaScript that ultimately would alter part of the page they were on.

    Being spoiled with AJAX, is there something simple I'm missing that would let me do this?
     
  2. digitalpoint

    digitalpoint Well-Known Member

    So if I turn off the data-direct and then plop my JavaScript straight into the alert message it seems to work... Seems a little kludgey though... Is this the best way?
     
  3. Jaxel

    Jaxel Well-Known Member

    @digitalpoint did you solve this issue? Because I solved it a while back (just found your message now), and wondering if you still need help with this.
     
  4. digitalpoint

    digitalpoint Well-Known Member

    To be honest, I forget what I was using it for, but yeah... pretty sure I just left it as it was (just plopped some JS to run in the alert message).
     
  5. Jaxel

    Jaxel Well-Known Member

    Well I solved this issue in some of my previous addons (XenRio and XenMedio). For instance, if you were editing/deleting a comment in XenMedio. Clicking on the link to edit/delete brings up a formOverlay. Clicking submit would then edit/delete the comment, and then alter that specific part of the page.

    Looking at a media page and it's comment list, its set up as follows:
    Code:
    <ol class="messageSimpleList">
        <li id="comment_9594" class="primaryContent messageSimple">...</li>
        <li id="comment_9590" class="primaryContent messageSimple">...</li>
        <li id="comment_9583" class="primaryContent messageSimple">...</li>
        <li id="comment_9582" class="primaryContent messageSimple">...</li>
        <li id="comment_9570" class="primaryContent messageSimple">...</li>
    </ol>
    As you can see, its a simple ordered list; but whats important to note is that each comment has a unique ID with the ID of that comment in the database. Within each comment list item, it has links to the overlays for editing and deleting:
    Code:
    <li id="comment_{$comment.comment_id}" class="primaryContent messageSimple">
        ...
        <a href="{xen:link 'media/comment/edit', $comment}" class="OverlayTrigger item">{xen:phrase edit}</a>
        <a href="{xen:link 'media/comment/delete', $comment}" class="OverlayTrigger item">{xen:phrase delete}</a>
        ...
    </li>
    Thats all thats really needed on the page you are editing. However, on the actual overlay forms, there is another piece of important information. If I use the edit form as an example:
    Code:
    <form action="{xen:link 'media/comment/edit', $comment}" method="post" id="CommentEditor"
        class="xenForm formOverlay AutoValidator" data-comment="{$comment.comment_id}">
        ...
    </form>
    It looks the same as any formOverlay, with an AutoValidator; but you'll notice two extra pieces of information. The first being the ID of "CommentEditor" and the data-comment ID parameter being passed to AJAX. This is everything thats needed in templates; the rest are php and js edits.

    ----
    The next thing is my actual php controller. On my software I use the same action for viewing a formOverlay and the actual process of the overlay (behind an isPost() confirmation).
    Code:
    public function actionCommentEdit()
    {
        ...
       
        if ($this->_request->isPost())
        {
            $comment = $this->getModelFromCache('EWRmedio_Model_Comments')->updateComment($input);
    
            if ($this->_noRedirect())
            {
                $viewParams = array(
                    'comment' => $comment,
                );
               
                return $this->responseView('EWRmedio_ViewPublic_MediaComment', 'EWRmedio_Bit_Comment', $viewParams);
            }
           
            return $this->responseRedirect(XenForo_ControllerResponse_Redirect::SUCCESS, XenForo_Link::buildPublicLink('media/media', $comment));
        }
    
        ...
    }
    Simple, if the action is a POSTed action, it updates the comment (otherwise it displays the update comment form). However, there is a "noRedirect()" trigger in the code. This noRedirect trigger activates when a form doesn't have a redirect; such as if it's getting fired by an AutoValidator AJAX call... basically when the responseView is JSON, instead of HTML. If it is an AJAX call, it takes the comment, and fetches the template for a comment bit. If its not an AJAX call (such as if someone has javascript disabled in their browser); it will degrade gracefully and do a standard responseRedirect.

    Thats all thats really needed in the php... next up is the javascript.

    -----
    The first thing you gotta do is register your trigger:
    Code:
    XenForo.register('#CommentEditor', 'XenForo.CommentEditor');
    Simple, any form with the ID of "CommentEditor" (which we set up earlier), will call the XenForo.CommentEditor function.

    The CommentEditor function is just as easy:
    Code:
    XenForo.CommentEditor = function($form)
    {
        $form.bind('AutoValidationComplete', function(e)
        {
            if (XenForo.hasTemplateHtml(e.ajaxData))
            {
                new XenForo.ExtLoader(e.ajaxData, function()
                {
                    $(e.ajaxData.templateHtml).xfInsert('replaceAll', '#comment_'+$form.data('comment'), 'xfShow');
                });
            }
        });
    }
    It binds to the form. After the form finishes validating, it simply replaces the div marked with the ID of "comment_{$comment.comment_id}" (which we also set up earlier) with the parsed template returned on the JSON call. Very simple stuff once you know how it works.


    For the delete function I did as follows:
    Code:
    XenForo.CommentDeleter = function($form)
    {
        $form.bind('AutoValidationComplete', function(e)
        {
            $('#comment_'+$form.data('comment')).xfRemove("xfFadeOut");
        });
    }
     
    Wuebit likes this.
  6. digitalpoint

    digitalpoint Well-Known Member

    Yeah, that's a "better" way to do it from a design standpoint, but meh... not sure I really care enough to add all the overhead. :)
     

Share This Page