We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 39932
    • 483 Posts
    This tutorial expounds upon my previous two tutorials and provides a practical use-case of the plugins: User Authentication. As compared to the other tutorials regarding this specific topic, there is very little that has to be done (in code). Unlike, the other tutorials in this series, I will be making some clear decisions as to the Javascript, and utilizing jQuery for the AJAX. This is simply to keep the code extremely light. Before embarking on this tutorial, it is advisable that you read the two linked below, as it uses their code and techniques.

    Relevant Tutorials



    Summarizing the Procedure

    Since we have already performed the steps performed in the first two tutorials, we will actually have very little legwork for this project. It takes about 15 minutes from start to finish. Unlike the other tutorials, we will simply be making a two documents, and a template. It will be demonstrated quite quickly what changes (very few) have to be made to enable this on your own installation.



    Creating the Login AJAX Resource

    Simply make a new Resource in the root of your 'web' Context. Name it "AJAX Login". Set the template to "Site Alias" from the second tutorial. Give it an alias of "login". Make it a container (for ease). In its content, place your [ [Login] ] call. (You may copy it from any of your templates or chunks.) Click Save.

    Note: For demonstration, you might want to set it with as many contexts as you can. smiley

    Refresh your cache! Now, right-click the Login and choose View Resource. We just want to make sure that it works. Now, feel free to try from any of your subdomain Contexts. (I still have yet to confirm/deny Babel Contexts)



    Creating the New Template

    1. Copy any one of your Templates that uses the Login Snippet.

    2. Add jQuery to your HTML Head. You may use the one from the CDN (Its quite fast)

        <script src="h.t.t.p.://code.jquery.com/jquery-1.7.2.min.js" type="text/javascript"></script>
    


    Note: The editor keeps malforming my code above, so it has been altered... Remove the periods from the h.t.t.p.

    3. Replace the Login Snippet call (completely) with the following code:

    <!-- This is where your Login will show up -->
        <div id="AjaxLogin" class="box"></div>
        <script type="text/javascript">
            $(document).ready(function()
            { 
                $.ajax({
                    type:"GET",
                    url:"/login/",
                    success:function(data)
                    { 
                        $("#AjaxLogin").html(data);
                    }, 
                    error:function(XMLHttpRequest, textStatus, errorThrown)
                    { 
                        $("#AjaxLogin").html(errorThrown + ": " + this.url);
                    }, 
                    dataType:"html"
                });
            });
        </script>
    


    Create a Dummy Page

    Just make a dummy page with dummy content like the "ipsum lorem" excerpt. Set it to your new template. It doesn't matter where you make it. Once you save it, try to "View Resource" it. It should show your AJAX Login page. If it doesn't, you should see a cute little error telling you why. If you don't, then you're not returning the data (even though it is finding it.



    Adjusting the Login Chunks

    If you got here, it's finding it, but clicking the Login button is not really useful (or requires a full refresh). That's easily solved!!

    Adjustng the Login Chunk

    Make a Back-up of your Login Chunk (not the Snippet). Now, open your Chunk and add this attribute to your cute little login submit button element... Take careful notice of the #AjaxLogin. If you changed the name of the id above, you'll have to fix it twice here. Also, note the .loginLoginForm. This needs to be whatever the CSS Selector would be for your form. (Mine is #Login to make it easy for me). The one provided is the default.

    onclick="$.ajax({ type:'POST', url:'/[[~[[*id]]]]', data:$('.loginLoginForm').serialize(), success:function(data){$('#AjaxLogin').html(data);}, error:function(error){$('#AjaxLogin').html(error);}, dataType:'html'});return false;"


    Alternatively, you could place the code in a function and call it instead. Just don't forget the "return false;" after the function call.

    Adjustng the Logout Chunk

    Add this code to your Logout Chunk's logout button. Again, notice the #AjaxLogin.

    onclick="$.get('[[+logoutUrl]]',function(data){$('#AjaxLogin').html(data);},'html');return false;"


    Testing your new Login

    Hopefully, you remembered to save both of these. Now, open that Dummy page we made. You shouldn't get a 404, unless you typed the URL wrong. If you get a 503, then you need to set the 'allow_forward_across_contexts' System Setting to "Yes".



    In Conclusion

    You just served Ajax Style Login without compromising security to your entire website without having to change much. We can do so with or without redirection (and even supply a redirection URL through an AJAX call, though this is NOT recommended). While it was pretty simple, there are some considerations.

    This example utilizes Login's security model, so if there are vunerabilities (which I'm not aware of any), you just accepted them site-wide. It does not degrade gracefully. To do this, you might place a link to a Login Page in your #AjaxLogin div. This will get overwritten by the jQuery GET if JavaScript is turned on. Because it uses your already in place Chunks, your CSS should still apply. The only difference is that your Login elements are in an extra div.



    Further Extensions

    You could add an event to the $.ajax calls to notify the rest of the page of a Login or Logout, so it could get/remove other components or redirect, if needed. This same model is being used on my site to supply:

    • Authentication from http.://domain.tld
    • Inline Help and Tooltips from http.://help.domain.tld
    • Tags and Tooltips(and their Info) from http.://tags.domain.tld
    • Specialized Intro Text and Tooltips from various sub-domains.

    Hope this helps! [ed. note: fuzzicallogic last edited this post 14 years, 1 month ago.]
      Website: Extended Dialog Development Blog: on Extended Dialog
      Add-ons: AJAX Revolution, RO.IDEs Editor & Framework (in works) Utilities: Plugin Compatibility List
      Tutorials: Create Cross-Context Resources, Cross-Context AJAX Login, Template-Based Actions, Remove Extensions from URLs

      Failure is just another word for saying you didn't want to try. "It can't be done" means "I don't know how".
      • 40828
      • 22 Posts
      I do it a bit differently:

      <script type="text/javascript">
      $(document).ready(function() {
        $('.loginLoginButton').click(function() {
          var action = 'lgn';
          var form = $('.loginForm form');
          var name = $( ".loginUsername" ),
              password = $( ".loginPassword" ),
              allFields = $( [] ).add( name ).add( password ),
              tips = $( ".loginMessage" );
      
          $.post('[[~14]]', {action:action}, function(data){
            $('.loginForm').html(data);
          })
          return false;
          })
      })
      </script>


      It basically gives the same result but for some reason I get {{+errors}} and other placeholders instead of its values. Do you get the placeholders parse correctly in your example? [ed. note: vzhilov last edited this post 14 years, 1 month ago.]
        • 39932
        • 483 Posts
        Yes, as a matter of fact, they do. But, you might want to wait for a day because I am making a major update to all 4 tutorials. They fix compatibility problems that address issues similar to the one you describe. For a preview of similar changes, you can check out my new Tutorial on Avoiding Extensions and Slash Issues (link in my signature).

        Note: The reason this happens is because the POST is not being processed correctly to the same URL. This can result in a successful login, but improper placeholders.
          Website: Extended Dialog Development Blog: on Extended Dialog
          Add-ons: AJAX Revolution, RO.IDEs Editor & Framework (in works) Utilities: Plugin Compatibility List
          Tutorials: Create Cross-Context Resources, Cross-Context AJAX Login, Template-Based Actions, Remove Extensions from URLs

          Failure is just another word for saying you didn't want to try. "It can't be done" means "I don't know how".
          • 39932
          • 483 Posts
          Updated: I mispoke. I don't know why yours is not parsing. Mine parses correctly because of how I get the resource ($modx->sendForward() in my other Tutorials). If you aren't using sendForward() or manually parsing the document, then it won't be parsed. I assume you are using getContent() to send it back?
            Website: Extended Dialog Development Blog: on Extended Dialog
            Add-ons: AJAX Revolution, RO.IDEs Editor & Framework (in works) Utilities: Plugin Compatibility List
            Tutorials: Create Cross-Context Resources, Cross-Context AJAX Login, Template-Based Actions, Remove Extensions from URLs

            Failure is just another word for saying you didn't want to try. "It can't be done" means "I don't know how".
            • 40828
            • 22 Posts
            I have

            $res = $modx->runSnippet('Login');


            I the processor and the above code to post. That's it. Is that the mistake?
              • 39932
              • 483 Posts
              No, it's not a mistake. But your runSnippet call also is not setting properties. Since it is not setting properties, you may only log into the 'web' context and therefore it won't work in any other context. It will let you type in what you need and it may log you in, but not to the context you want to be logged in to. So it will always show you the wrong everything.

              You can either a) add the properties manually; b) just change the URL to a Resource that has only the Login call, like my tutorial; or c) change the default properties of Login (not recommended).

              [[!Login? ... ...]]
              


              This is why my AJAX Framework does not bother with REST libraries and such. It just gets partial pages using URL as partial data transport mechanism. The URL goes to a page that has nothing but the Login tag.

              Since your code is different, you might consider trying to apply my tutorials tomorrow after they are updated (without getting rid of yours) and see how they differ from your technique. It's not all about the JavaScript and PHP. A lot of it has to do with handling the URL structure and retrieving the Resources correctly.

              Update: You will know they are updated because on the first line, it will say "Updated on 8/19/2012" [ed. note: fuzzicallogic last edited this post 14 years, 1 month ago.]
                Website: Extended Dialog Development Blog: on Extended Dialog
                Add-ons: AJAX Revolution, RO.IDEs Editor & Framework (in works) Utilities: Plugin Compatibility List
                Tutorials: Create Cross-Context Resources, Cross-Context AJAX Login, Template-Based Actions, Remove Extensions from URLs

                Failure is just another word for saying you didn't want to try. "It can't be done" means "I don't know how".
                • 40828
                • 22 Posts
                Ok. So I did two your previous updated tutorials and it seems working. SInce I'm just a begginer that was a great help. Now I got stuck on thei Ajax Login again. First, in the chapter "Creating the Login AJAX Resource", end of first paragraph it says:
                "Make it a container (for ease). In its content, place your ." This seems like an incompleted sentence. Maybe I'm missing something right there.

                Then the error I get in output is "Not Found: /login/". Which I belive due to my friendly URLs are not adjusted. I can call pages only by "index.php?id=1" etc. and not by aliases. I think you had something on that in your previous tutorials but now I can't find it.
                  • 39932
                  • 483 Posts
                  "Make it a container (for ease). In its content, place your .

                  Doht. You're absolutely correct... incomplete sentence... This is supposed to say Login call:

                    [[!Login?
                      ...
                      ...
                    ]]
                  


                  I can call pages only by "index.php?id=1"...

                  OMGosh, I have just assumed (when making the tutorials) that everyone is using Friendly URLs. This makes it a little more difficult. Is there some reason you have not converted to FURLs? If not, can that be easily done? If not, the solution is simple, but needs to be tweaked just slightly. My URLs avoid messing with the GET params (so as to not to screw with queries).

                  Also, if the other tutorials have worked, that is not entirely true... It will still get pages using the aliases, but there are going to be quibbles in many places. And they aren't going to be fun. These plugins avoid using IDs as parameters.

                  Possible Easy Fix:

                  In that case, you will want to use the URL "/login/ajax/" specifically... This will force the Plugin to fire, rather than allowing it to use its judgement... If this doesn't work. I can adjust to your specific needs but it may take a day or two as all of my sites use Friendly URLs, I would have to make a cloud and test with non-friendly URLs. [ed. note: fuzzicallogic last edited this post 14 years, 1 month ago.]
                    Website: Extended Dialog Development Blog: on Extended Dialog
                    Add-ons: AJAX Revolution, RO.IDEs Editor & Framework (in works) Utilities: Plugin Compatibility List
                    Tutorials: Create Cross-Context Resources, Cross-Context AJAX Login, Template-Based Actions, Remove Extensions from URLs

                    Failure is just another word for saying you didn't want to try. "It can't be done" means "I don't know how".
                    • 40828
                    • 22 Posts
                    No, no, I would love to use friendly URLs, I just don't know how. I did some settings but it didn't help.
                      • 39932
                      • 483 Posts
                      Here, go to this tutorial (in the MODx Documentation). It works for nearly all setups. After you do it, you have to clear the cache though.

                      The most important part is the .htaccess. Do that step first... then you can use the FURLs System Settings.
                        Website: Extended Dialog Development Blog: on Extended Dialog
                        Add-ons: AJAX Revolution, RO.IDEs Editor & Framework (in works) Utilities: Plugin Compatibility List
                        Tutorials: Create Cross-Context Resources, Cross-Context AJAX Login, Template-Based Actions, Remove Extensions from URLs

                        Failure is just another word for saying you didn't want to try. "It can't be done" means "I don't know how".