Use the angular plug-in to create a website User Guide effect

Source: Internet
Author: User
Tags foreach bind constant extend

In order to allow users to adapt to the new Web site, introduced in the system "user-led" function, for most sites, this is a very common function. So before you develop this task, try to abstract it, separate it from the business logic of your existing system, and encapsulate it as a general-purpose plug-in, making it easier to extend and maintain your code.

Looks like a look at the effect chart

The use of this trainning plug-in is simple, it takes the same configuration as angular routing, simply configure each step training information.





Title:step the title of the information;


Template/templateurl:step the content template information. This class can configure HTML elements, or the URL address of the template, while Templateurl also supports the same function syntax as angular route;


Controller:step controller configuration; The following parameters can be injected into the controller: current step? Currentstep, all step configuration? Trainnings, the current step configuration? Currenttrainning, and the next action callback? Trainninginstance (where NeXTSTEP: For the next callback, Cancel to cancel the user boot callback);


The alias of the Controlleras:controller;


Resolve: Data configuration before controller initialization, with resolve in angular routing;


Locals: local variables, similar to resolve, can be passed into the controller. The difference is that it does not support function calls and is more convenient for constant writing than for resolve;


Placement:step the display azimuth of the triangular arrows on the container,


The exact display position of the Position:step container, which is an absolute coordinate, the absolute coordinates of {left:100, top:100} can be passed, or the placement location of the #steppanelhost configuration relative to this element. It also supports custom function and other component syntax for injecting angular. And the default can be injected: all step configurations? Trainnings, what's the current step? Step, the current step configuration? Currenttrainning, and the Step container node? Steppanel;


Backdrop: Whether the mask layer needs to be displayed, by default, the mask layer is not displayed unless the display is declared as false;


Stepclass: The style information of each step container;


Backdropclass: Style information for each matte layer.





After understanding these configurations and customizing the entire user-booted configuration information based on specific requirements, we can use the Trainningservice trainning method to launch the user boot in a specific practical way, passing in the parameters for each step of the configuration information. and may register its done or cancel event:





Trainningservice.trainning (trainningcourses.courses)


. Done (function () {


Vm.isdone = true;


});





Here is a demo of the configuration information:





. Constant (' trainningcourses ', {


Courses: [{


Title: ' Step 1: ',


Templateurl: ' trainning-content.html ',


Controller: ' Steppanelcontroller ',


Controlleras: ' Steppanel ',


Placement: ' Left ',


Position: ' #blogControl '


},{


Title: ' Step 3: ',


Templateurl: ' trainning-content.html ',


Controller: ' Steppanelcontroller ',


Controlleras: ' Steppanel ',


Placement: ' Top ',


Position: {


TOP:200,


left:100


}


},


...


{


Stepclass: ' Last-step ',


Backdropclass: ' Last-backdrop ',


Templateurl: ' trainning-content-done.html ',


Controller: ' Steppanelcontroller ',


Controlleras: ' Steppanel ',


Position: [' $window ', ' Steppanel ', function ($window, Steppanel) {


Custom function to center its screen


var win = angular.element ($window);


return {


Top: (Win.height ()-steppanel.height ())/2,


Left: (Win.width ()-steppanel.width ())/2


}


}]


}]


})





This article plug-in source and demo effect only Codepen, the effect is as follows:

<div ng-app= "Com.github.greengerong"  ng-controller= "Democontroller as demo" >  
   <div class= "Alert alert-success fade in"  ng-if= ' Demo.isDone ' >         <strong>all trainning setps done!</ strong>     </div>     <button id= "Startagain"   class= "Btn btn-primary start-again"  ng-click= "demo.trainning ()" >you can start  trainning again</button>     <div class= "blog" >          <form class= "Form-inline" >              <div class= "Form-group" >                  <label class= "Sr-only"  for= " Exampleinputamount ">blog :</label>                  <div class= "Input-group" >                      <input id= "BlogControl"  type= "text"   class= "Form-control"  />                  </div>             </div >             <button id= "SubmitBlog"  class= "Btn btn-primary"  ng-click= "Demo.backdrop ()" >Public blog</button>          </form>     </div>      <script type= "Text/ng-template"  id= "modal-backdrop.html" >          <div class= ' Modal-backdrop fade in {{backdropclass}} '  ng-style= ' {' Z-index ':  zindex | |  1040} "></div>     </script>     <script  Type= "Text/ng-template"  id= "trainning-step.html" >         < div class= "Trainning-step" >              <div style= "display:block; z-index:1080;left:-1000px;top:-1000px;"  ng-style= "Positionstyle"  class= "step-panel {{currenttrainning.placement}} fade  Popover in {{currenttrainning.stepclass}} " ng-show="!isprogressing >                  <div class= "Arrow" ></div >                 <div  class= "Popover-inner" >                      <h3 class= "Popover-title"  ng-if= ' Currenttrainning.title ' >{{currenttrainning.title}}</ H3>                      <div class= "Popover-content" >                      </div>                  </div>              </div>              <ui-backdrop backdrop-class= "Currenttrainning.backdropclass"  ng-if= " Currenttrainning.backdrop !== false "></ui-backdrop>          </div>     </script>     <script type= "Text/ng-template"  id= "Trainning-content.html" >         <div class= "step-content" >             <div>{{ steppanel.texts [Steppanel.currentstep - 1]}} </div>             <div class= " Next-step ">               <ul  class= "Step-progressing" >              
   <li data-ng-repeat= "Item in steppanel.trainnings.length | range"                   
  data-ng-class= "{Active: steppanel.currentstep == item}" >                </li>             </ul>                  <button type= "button"   class= "Btn btn-link btn-next pull-right"  ng-click= "StepPanel.trainningInstance.nextStep" ({$ Event: $event,  step:step});
>Next</button>             </div>         </div>            </script>     <script type= "Text/ng-template"  id= " Trainning-content-done.html ">         <div class="
Step-content ">              <div>     {{ STEPPANEL.TEXTS[STEPPANEL.CURRENTSTEP - 1]}}            </div>              <div class= "Next-step" >                <ul class= "Step-progressing" >                  <li data-ng-repeat= "item in  Steppanel.trainnings.length | range "                     data-ng-class= "{Active: steppanel.currentstep  == item} ">               
  </li>             </ul>        &nBsp;        <button type= "button"  class= "btn  Btn-link  pull-right " ng-click=" NextStep ({$event: $event,  step:step}); " >Got it</button>             </div >         </div>     </script> </ Div>
. last-step{ /* background-color: blue;*/}. last-backdrop{  background-color: #
FFFFFF; }. blog{  position: absolute;   left: 300px;   top: 100px;}. start-again{  position: absolute;   left: 400px;   top: 250px;}. next-step {  .step-progressing {      margin: 10px
 0px;
      display: inline-block;       li {        margin-right:
 5px;
        border: 1px solid  #fff;
        background-color:  #6E6E6E;
        width: 12px;
        height: 12px;         border-radius: 50%;
        display: inline-block;         &.active {       
   background-color:  #0000FF;         }             }
}


Please set step content to fixed width when complex content
 or dynamic loading. Angular.module (' Com.github.greengerong.backdrop ',  [])     .directive (' Uibackdrop ',  [' $document ',  function ($document)  {        return  {            restrict:  ' EA ',              replace: true,              templateUrl:  ' modal-backdrop.html ',              scope: {                 backdropClass:  ' = ',                  zIndex:  ' = '             }              /* ,link: function () {                 $document. Bind (' KeyDown ',  function (evt) {     
            evt.preventdefault ();                  
Evt.stoppropagation ();
               });                    
            scope. $on (' $destroy ',  function () {                  $
Document.unbind (' KeyDown ');                 });              }*/    
    };    &NBSP}])     .service (' Modalbackdropservice ',  [' $rootScope ',  ') $compile ',  ' $document ',  function ($rootScope,  $compile,  $document)  {   
     var self = this;         self.backdrop = function (BackdropClass, zIndex)  {            var  $backdrop  =  Angular.element (' <ui-backdrop></ui-backdrop> ')                  .attr ({                    &nBSP; ' Backdrop-class ':  ' Backdropclass ',                       ' Z-index ':  ' ZIndex '       
          });             var backdropscope = $
Rootscope. $new (True);             backdropscope.backdropclass =
 backdropClass;             backdropScope.zIndex = 
ZIndex;              $document. Find (' body '). Append ($compile ($backdrop)
(Backdropscope));             return function ()  {                  $bacKdrop.remove ();                 backdropscope.
$destroy ();
            };
        };
   &NBSP}]); Angular.module (' com.github.greengerong.trainning ',  [' com.github.greengerong.backdrop ',  ' ui.bootstrap ']     .directive (' Trainningstep ',  [' $timeout ',  ' $http ',  ' $templateCache ',   ' $compile ',  ' $position ',  ' $injector ',  ' $window ',  ' $q ',  ' $controller ',  function ($timeout,  $http,  $templateCache,  $compile,  $position,  $injector,  $ window,  $q,  $controller)  {        return {             restrict:  ' EA ',              replace:  true,             templateUrl:  '
Trainning-step.html ',             scope: {                 step:  ' = ' ,                 trainnings:   ' = ',                  nextstep:  ' & ',               
  cancel:  ' & '             },             link: function (StepPanelScope,  elm)  {                 var steppanel = elm.find ('. Step-panel ');                 steppanelscope . $watch (' Step ',  function (step)  {                     if  (!step)  {                        
 return;                      }                      steppanelscope.currenttrainning = steppanelscope.trainnings[
steppanelscope.step - 1];                      var contentscope = steppanelscope. $new(false);                      loadstepcontent (contentscope, {                          ' Currentstep ':  Steppanelscope.step,                           ' trainnings ':  steppanelscope.trainnings,                            ' currenttrainning ':  steppanelscope.currenttrainning,                            ' trainninginstance ':  {                              ' NextStep ':  Steppanelscope.nextstep,                               ' Cancel ':  Steppanelscope.cancel                          }         
           &NBSP}). Then (function (Tplandvars)  {                   
      elm.find ('. Popover-content '). HTML ($compile (tplandvars[0)) (Contentscope);                     &NBSP}). Then (function ()  {                   
     var pos = stepPanelScope.currentTrainning.position;                   
      adjustposition (Steppanelscope, steppanel, pos);                   
  });
                });                  Angular.element ($window). bind (' Resize ',  function ()  {                     adjustposition (stepPanelScope,  Steppanel, steppanelscope.currenttrainning.position);
                });                 steppanelscope . $on (' $destroy ',  function ()  {           
         angular.element ($window). Unbind (' resize ');
                });                 function  Getpositiononelement (stepscope, setppos)  {                     return  $position. Positionelements (
Angular.element (Setppos),  steppanel, stepscope.currenttrainning.placement, true);                 }                  function positiononelement (stepscope, setppos)  {                     var  targetpos = angular.isstring (Setppos)  ? getpositiononelement (StepScope, setpPos
)  : setpPos;                      var positionstyle = stepscope.currenttrainning | |
 {};                   
  positionStyle.top = targetPos.top +  ' px ';                      positionstyle.left = targetpos.left +  ' px ';                   
  stepScope.positionStyle = positionStyle;                 }                  function  Adjustposition (stepscope, steppanel, pos)  {                     if  (!pos)  {                     
    return;                      }                      var  Setppos = angular.isfunction (POS)  | |  angular.isarray (POS)  ?  $injector. Invoke (pos, null, {                          trainnings: stepscope.trainnings,                          STEP: STEPSCOPE.SETP,                           currenttrainning: stepscope.currenttrainning,                           steppanel: steppanel              
      &NBSP})  : pos;                      Get postion should wait for content setup       
               $timeout (function ()  {                   
      positiononelement (Stepscope, setppos);                   
  });                 }                  function  Loadstepcontent (contentscope, ctrllocals)  {                      var trainningoptions = contentscope.currenttrainning,                           gettemplatepromise = function (options)  {                              return options.template ?  $q. When (options.template)  :                                    $http. Get (Angular.isfunction ( Options.templateurl)  ?  (Options.templateurl) ()  : options.templateurl, {                                      cache:  $templateCache                                  &NBSP}). Then (function (result)  {                                      return
 result.data;                   
              });                         &NBSP},                           getresolvepromises = function (resolves)  {                   
          var promisesArr = [];                              angular.foreach (resolves, function (value)  {                                 if  ( Angular.isfunction (value)  | |  angular.isarray (value))  {                                  &nbsP;   promisesarr.push ($q. When ($injector. Invoke (value));                                  }                        
      });                   
          return promisesArr;                         &NBSP},                          controllerloader = function ( Trainningoptions, trainningscope,&nBsp;ctrllocals, tplandvars)  {                             var
 ctrlInstance;                              ctrllocals = angular.extend ({},  ctrllocals | |  {}, trainningoptions.locals | |
 {});                   
          var resolveIter = 1;                              if  (Trainningoptions.controller)  {                             
    ctrllocals. $scope  = trainningScope;                                  angular.foreach ( Trainningoptions.resolve, function (value, key)  {                                      ctrllocals[key] = tplandvars[
Resolveiter++];                   
              });                                 
ctrlinstance =  $controller (trainningoptions.controller, ctrllocals);                                  if  ( Trainningoptions.controlleras)  {                               
      trainningScope[trainningOptions.controllerAs] = ctrlInstance;                                  }                              }                        
      return trainningScope;                   
      };                      var templateAndResolvePromise =  $q. All ([Gettemplatepromise (Trainningoptions)]. Concat (getresolvepromises, trainningoptions.resolve | |
 {}));                      return templateandresolvepromise.then (function resolvesuccess (tplAndVars)  {              &nBsp;          controllerloader (trainningOptions, 
Contentscope, ctrllocals, tplandvars);                   
      return tplAndVars;                   
  });                 }              }         }
;    &NBSP}])     .service (' Trainningservice ',  [' $compile ',  ' $ Rootscope ',  ' $document ',  ' $q ',  function ($compile,  $rootScope,  $document,  $q)  {        var self = this;       &nBsp;  self.trainning = function (trainnings)  {             var trainningScope =  $rootScope. $new (True),                  defer =  $q. Defer (),                  $STEPELM  = angular.element (' <trainning-step></trainning-step> ')                  .attr ({                      ' Step ':  ' step ',                        ' trainnings ':  ' trainnings ',                       ' next-step ':  ' NextStep ($event,  step); ',                       ' Cancel ':  ' Cancel ($event,  step) '                 &NBSP}),                  destroytrainningpanel = function () {                   if  (trainningscope)  {                       $
Stepelm.remove ();                   
    trainningscope. $destroy ();                   }            
     };                           trainningscope.cancel = function ($event,  step) {  
            defer.reject (' Cancel ');
            };                         trainningscope.nextstep = function ($event,  step)  {                 if  ( Trainningscope.step === trainnings.length)  {                 &nBsp;   destroytrainningpanel ();                   
  return defer.resolve (' done ');                 }   
              trainningScope.step++;
            };             trainningScope.trainnings = 
Trainnings;
            trainningScope.step = 1;              $document. Find (' body '). Append ($compile ($STEPELM)
(Trainningscope));              $rootScope. $on (' $locationChangeStart ',  destroytrainningpanel);                         return {                 done: function (func)  {         
           defer.promise.then (func);                &NBSP},                  cancel: function (func )  {                 
   defer.promise.then (Null, func);                 }   
          };         };
   &NBSP}]); Angular.module (' Com.github.greengerong ',  [' com.github.greengerong.trainning '). Filter (' Range ',  [ function  ()  {            return  function  (len)  {              
  return _.range (1, len + 1);
    };    &NBSP}])     .controller (' Steppanelcontroller ',  [' currentStep '),   ' trainnings ',  ' trainninginstance ',  ' trainnings ',  function (Currentstep, trainnings,  trainninginstance, trainnings)  {        VAR VM
 = this;
        vm.currentStep = currentStep;         vm.trainninginstance = trainninginstance;
        vm.trainnings = trainnings;         vm.texts = [' Write your own sort  blog ',  ' click button to public your blog. ',  ' View your  Blog info on there ',  ' click this button, you can restart 
this trainning when  ',  ' all trainnings done! '];
        return vm;    &NBSP}])     .constant (' trainningcourses ',  {         courses: [{             title:  ' step 1: ',              templateUrl:  ' trainning-content.html ',              controller:  ' Steppanelcontroller ',              controlleras:  ' Steppanel ',              placement:  ' left ',             position:  ' #blogControl '         }, {             title:  ' step 2: ',              templateUrl:  ' trainning-content.html ',              controller:  ' Steppanelcontroller ',              controllerAs:  ' Steppanel ',              placement:  ' right ',              bAckdrop: false,             position:  ' # Submitblog '         }, {             title:  ' step 3: ',              templateUrl:  ' trainning-content.html ',              controller:  ' Steppanelcontroller ',              controllerAs:  ' Steppanel ',              placement:  ' top ',              position: {                 top: 200,                  left: 100                       }, {             title:  ' step 4: ',              templateurl:  ' trainning-content.html ',              controller:  ' Steppanelcontroller ',              controllerAs:  ' Steppanel ',              placement:  ' Bottom ',              position:  ' #startAgain '         }, {             stepClass:  ' Last-step ',              backdropClass:  ' Last-backdrop ',              templateUrl:  ' trainning-content-done.html ',              controller:  ' Steppanelcontroller ',              controllerAs:  ' Steppanel ',              position: [' $window ',  ' Steppanel ',  function ($window,  steppanel)  {                var
 win = angular.element ($window);
                return {                      top:  (Win.height ()  - steppanel.height ())  / 2, &NBsp;                    left:  (Win.width ()  - steppanel.width ())  / 2                  }        
    &NBSP}]         }]    &nbsp     .controller (' Democontroller ',  [' trainningservice ',  ' trainningCourses '),  ' Modalbackdropservice ',  function (Trainningservice, trainningcourses, modalbackdropservice)  {        var vm = this;          vm.trainning = function ()  {                       //call this  Service should&nbSp;wait your really document ready event.           trainningservice.trainning ( trainningcourses.courses)                  .done (function ()  {            
        vm.isDone = true;
                });
        };
        var backdropInstance = angular.noop;         vm.backdrop = function ()  {   
         modalbackdropservice.backdrop ();
        };         vm.traiNning ();
        return vm;    &NBSP}]);

Run Effect chart


The source design of the Trainning plug-in includes the following points:

    provide service APIs. Because about trainning this plug-in, it is a global plug-in, just in angular all the service is also a single example, so the user guidance logic encapsulated into the angular service is a good design. However, for each step of trainning, the content information is DOM operation, in angular processing it should not exist in the service, the best way is to encapsulate him in the directive. So here the definition of directive, and in the service compile, and then append into the body.
    for each such standalone plug-in should encapsulate a separate scope that facilitates subsequent destruction and does not conflict with existing scope variables.
    $q Wrap The result of a delay trigger. It is a good choice to use promise encapsulation for such operations as the Trainning plug-in or modal. It replaces the complexity of callback parameters and is presented in a fluent API, which is more readable to the code. It also can be integrated with other angular service to return the API.
    for similar routes such as Controller, Controlleras, resolve, template, Templateurl, can be moved to your same plug-in. They can add more customization extensions to plug-ins. On this part of the code explanation, the blogger will be in the follow-up article for everyone to push.
    uses $injector.invoke to dynamically inject and invoke angular service, so as to gain the extensibility of angular other service injection, as well as to obtain the dynamic nature of the function. As shown in the previous example, the custom extension method is centered on the screen. The design essentials such as

can also be applied to global plug-ins such as modal, alert, and overload.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.