37 Replies · Latest reply on Jan 4, 2018 8:58 AM by Dave Slusher

    Ask the Expert: Service Portal Part 2, TechNow 29

      expert-logo-2.png

       

      Join Chuck Tomasi and Dave Slusher as they continue their discussion on Service Portal based on your input! We get in to some more advanced topics around creating widgets and solving problems you asked about. Service Portal is the Helsinki developer feature with the most excitement behind it and for good reason. Come see why!

       

       

      Join us live Wednesday August 17, 12:00PM PDT 
      (Be sure to change your YouTube Setting to 720HD)

       

      Ask your questions below on this discussion page.

      And Please Let our Expert Know how they've helped! Comment Below!

      Like, Share, Mark Helpful.

       

      Please Like and Share!  Find More Events on the Community!

       

      Find Part 1 Here Ask the Expert: Service Portal, TechNow 28

       


      Featured Experts

       

      Chuck Tomasi is a Platform Architect for ServiceNow.  He is a computer science major with over 30 years of IT experience. As a former ServiceNow customer, Chuck won the first Innovation of the Year Award at Knowledge 10. Since joining ServiceNow in 2010 as a Technical Consultant, he has done many large scale ITSM implementations and custom applications, acted as an adjunct instructor for Education Services, created and lead the Technical Best Practices program, and co-hosts the ServiceNow series “TechNow”.

       

      Dave Slusher has been developing software for 20 years for companies such as Intel, Orbitz, Dell Secureworks and many startups lost to history. He has been with ServiceNow for two years, first in Expert Services and now as the Developer Evangelist for the developer community and portal. He earned his BS from Georgia Tech and his MS in Computer Science from the University of Louisiana - Lafayette.

       

       

      Kreg Steppe is an Automation Consultant within ServiceNow's Orchestration product. He specializes in developing integration solutions and automating repeatable processes. Kreg's prior experience includes managing Network Support and Application Development on cloud based networks and DNS maintenance for Manager Tools.

        • Re: Ask the Expert: Service Portal Part 2, TechNow 29
          AJ Aqunio

          In the old CMS we were able to easily display gauges/reports that we already had, is there an easy way to do that on the new Service Portal?

           

          Thanks.

          • Re: Ask the Expert: Service Portal Part 2, TechNow 29
            Dave Slusher

            Are you talking about Service Portal widgets or something else? I don't know of any widespread issues like this with either one. Can you give us some more detail about exactly what is having the problem?

            Dave Slusher | Developer Advocate | @DaveSlusherNow | Get started at https://developer.servicenow.com

            • Re: Ask the Expert: Service Portal Part 2, TechNow 29
              Nathan Firth

              Question... why when updating the incident are you using the REST API instead of just doing it inside the Server Script?

              --------------------------------
              Nathan Firth
              Principal ServiceNow Architect
              nathan.firth@newrocket.com
              http://newrocket.com
              http://serviceportal.io

                • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                  Chuck Tomasi

                  Good question Nathan. We should get in touch if there are other methods.

                  --Chuck Tomasi
                  --Sr. Technical Product Marketing Mgr, Now Platform
                  --Join me on the Community live stream (most) weekdays at 8:00AM ET
                  --https://youtube.com/user/servicenowcommunity

                  • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                    Nathan Firth

                    To answer my own question:

                     

                    In the controller you could do:

                    c.data.update_incident = c.data.sys_id; // or whatever

                    // this will take "data" and send it back to the server script as "input"

                    c.server.update().then(function(response){

                         c.data.update_incident = undefined;

                    })

                     

                    And in server script:

                    if (input && input.update_incident) {

                         // Do GlideRecord update of incident here

                         // input.update_incident is the sys_id of the record

                    }

                    4 of 4 people found this helpful

                    --------------------------------
                    Nathan Firth
                    Principal ServiceNow Architect
                    nathan.firth@newrocket.com
                    http://newrocket.com
                    http://serviceportal.io

                      • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                        quiksilver

                        Hi Nathan,

                         

                        Thanks for this post.  It is very helpful.

                         

                        Quick question though

                        This line

                        c.data.update_incident = c.data.sys_id;

                         

                        This is passing data from c back to data? Can this line work alone? or it needs c.server.update?

                         

                        The reason I am asking is because in I am looking for a way to get widget sys_id and i found out I can get it via c.widget.sys_id.  But I need it in the server script so I was looking at your post to pass this to the server script

                         

                        Thanks for your reply

                         

                        Broderick

                          • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                            Nathan Firth

                            Anything on data gets passed as "input" to the server when you use server.update(). I just put the sys_id there as convention but you could also have used: c.data.update_incident=true; and then on the server grab the ID from input.sys_id;

                            --------------------------------
                            Nathan Firth
                            Principal ServiceNow Architect
                            nathan.firth@newrocket.com
                            http://newrocket.com
                            http://serviceportal.io

                          • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                            William Smith

                            Hi nathanfirth, thanks for the update on the server script. Would you mind fleshing out the rest of the server side code to mimic what Dave is attempting to accomplish with updating an incident? You had mentioned the following but I'm not sure what the GR update of the incident would look like? With the following code I am finding that pressing the Save button doesn't save the incident record update back to the incident. What would I need to update in my client/server script to get this functioning?

                             

                            As a side note, the client script logging is outputting the updated short description, I'm just not seeing an update on the server - so that at least narrows down the issue to my server script.

                             

                            I have the following in the client script:

                            $scope.save = function saveRecord() {
                                        //$scope.writeIncident($scope.editingRecord.sys_id, 
                                            //                                     {'short_description': $scope.editingRecord.short_description});
                                    
                                    // this will take "data" and send it back to the server script as "input"
                            /*Anything on data gets passed as "input" to the server when you use server.update().
                            I just put the sys_id there as convention but you could also have used: c.data.update_incident=true;
                            and then on the server grab the ID from input.sys_id;
                            */
                                c.data.update_incident = c.data.sys_id;
                            
                                c.server.update().then(function(response){
                                 c.data.update_incident = undefined;
                            })
                                    
                                    $log.debug(">>> SHORT DESCRIPTION: " + $scope.editingRecord.short_description);
                                    $scope.reset();
                                };
                            

                             

                             

                            And in server script:

                            if (input && input.update_incident) {
                            // Do GlideRecord update of incident here
                            // input.update_incident is the sys_id of the record
                                input.update_incident.update();
                                gs.info("SYS_ID= " + input.update_incident);
                            }
                            

                            -------
                            Please remember to mark my reply as helpful or correct if you agree that it was. :)

                              • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                Brad Tilton

                                I think input.update_incident would just be the sys_id so you'd have to do a GlideRecord update. Something like:

                                 

                                if (input && input.update_incident) { 
                                // Do GlideRecord update of incident here 
                                // input.update_incident is the sys_id of the record 
                                    var inc = new GlideRecord('incident');
                                    if (inc.get(input.update_incident)) {
                                    //set a value
                                    inc.update();
                                    }
                                } 
                                
                                1 of 1 people found this helpful
                          • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                            Dave Slusher

                            nathanfirth Thanks. Can you tell me a little about the underlying implementation? My assumption is that return path through the server script is also some AJAX happening. Is there a compelling reason to do it one way over the other from an efficiency or runtime standpoint? I kind of like not having to put extra code in the server script for the saving personally but that may be just because this was what was recommended to me as I was learning.

                            Dave Slusher | Developer Advocate | @DaveSlusherNow | Get started at https://developer.servicenow.com

                              • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                Nathan Firth

                                dave.slusher Sure, yes so behind the scenes it is doing an AJAX call back to the server script. There is nothing wrong with using the REST API, but there are quite a few reasons why using the Server Script. Some reasons:

                                 

                                • It keeps the widget self contained with all the logic available from within the widget editor
                                • You can handle complex logic beyond just inserts and updates
                                • You can specify as many actions as you want
                                • You have access to all your functions, logic, and $sp methods
                                • When calling the server, it automatically passes the entire "data" object and makes it available on server

                                So for a quick example of how this could work... I generate some data on the server, then manipulate/change it in the controller or UI, then by simply calling c.server.update() you now pass all of that data back to the server, process it... and then automatically update scope and refresh the page.

                                4 of 4 people found this helpful

                                --------------------------------
                                Nathan Firth
                                Principal ServiceNow Architect
                                nathan.firth@newrocket.com
                                http://newrocket.com
                                http://serviceportal.io

                              • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                Dave Slusher

                                nathanfirth Thank you for clarifying. I'll work up some examples of doing that in the future. I'll be honest, when the only thing that is happening is raw, untransformed persistence of the data, I still like the API hit in controller. I like that it makes explicit and understandable what is happening. However, I do understand what you are saying about the complex logic and logic spread out in multiple places. I'll make sure I communicate both scenarios going forward.

                                1 of 1 people found this helpful

                                Dave Slusher | Developer Advocate | @DaveSlusherNow | Get started at https://developer.servicenow.com

                                  • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                    Chuck Tomasi

                                    Greatest online community EVAR!

                                    --Chuck Tomasi
                                    --Sr. Technical Product Marketing Mgr, Now Platform
                                    --Join me on the Community live stream (most) weekdays at 8:00AM ET
                                    --https://youtube.com/user/servicenowcommunity

                                    • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                      Andrew Lawlor

                                      Excellent video - I'm really enjoying this series.

                                       

                                      Quick question:

                                       

                                      What is the effective difference between defining your client-side functions on the Controller object vs. the $scope object? In this video, you define your functions on the $scope object, but I've also seen some examples of functions getting defined on the c (controller object).

                                      1 of 1 people found this helpful
                                        • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                          Dave Slusher

                                          Like I try to caution, at this point with Service Portal I'm not declaring anything I do best practice or good practice or anything other than "it works." The true answer is that is how some of the example code I saw did it. I could be talked into declaring them in the controller object being the best practice. Doing it in the $scope makes them available to the HTML template without any further prefixing and it doesn't really seem to make that much of a difference where in the controller you declare them.

                                           

                                          Like everything in this space, I'm eager to be corrected if I'm saying something wrong.

                                          Dave Slusher | Developer Advocate | @DaveSlusherNow | Get started at https://developer.servicenow.com

                                      • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                        Manish verma

                                        I am trying to create small widget with tabs like feature, but the code does not show data in the widget designer, whereas the data is visible when the widget is added to a portal page. Can you check the issue?

                                        Widget designer:

                                        On Portal page the data is visible:

                                         

                                        HTML:

                                        =====================

                                        <div>

                                        <section>

                                          <ul ng-init="tab = 1">

                                          <li ng-class="{active:tab===1}">

                                          <a href ng-click="tab = 1">Learn how to</a>

                                          </li>

                                          <li ng-class="{active:tab===2}">

                                          <a href ng-click="tab = 2">Report an Incident</a>

                                          </li>

                                          <li ng-class="{active:tab===3}">

                                          <a href ng-click="tab = 3">Submit a request</a>

                                          </li>

                                          <br><br>

                                          <div ng-show="tab === 1">

                                              <table>

                                                <tr>

                                                  <td colspan="2">

                                                    Number of Articles:: {{data.number}}

                                                  </td>

                                                </tr>

                                                <tr ng-repeat="count2 in data.count">

                                                  <td>

                                                   {{count2.category}}

                                                  </td>

                                                  <td>

                                                    {{count2.category_count}}

                                                  </td>

                                             

                                                

                                              </table>

                                              </div>

                                          <p ng-show="tab === 2"> Tab2... </p>

                                          <p ng-show="tab === 3"> Tab3...</p>

                                          </ul>

                                          </section>

                                         

                                         

                                        </div>

                                        =================================

                                        CSS:

                                        =====================================

                                        p {

                                          font-size: 22px;

                                          font-weight: bold;

                                          font-style: italic;

                                          color: rgb(62, 62, 62);

                                          margin: 18px;

                                          }

                                          ul {

                                          float: left;

                                          border-radius: 5px;

                                          border: solid 1px rgb(198, 198, 198);

                                          padding: 7px 11px;

                                          background-color: rgb(248,248,248);

                                          }

                                          li {

                                          float: left;

                                          background-color: rgb(200,200,200);

                                          padding: 5px 19px;

                                          margin: 5px 2px 5px 0px;

                                          color: black;

                                          list-style: none;

                                          }

                                          li:hover, li:hover a {

                                          background-color: rgb(6,179,6);

                                          color:white;

                                          }

                                          li a {

                                          text-decoration: none;

                                          color: white;

                                          font-size: 21px;

                                          text-shadow: 1px 0px 3px rgb(157, 157, 157);

                                            text-transform: uppercase

                                          }

                                          li:nth-child(1) { border-radius: 4px 0px 0px 4px; margin-left: 1px;}

                                          li:nth-child(3) { border-radius: 0px 4px 4px 0px;}

                                          .active {

                                          background-color: rgb(6,179,6);

                                          }

                                         

                                         

                                        td {

                                          width: 315px;

                                            height: 73px;

                                            margin-top:20px;

                                            margin-left: 20px;

                                            text-align: center;

                                            padding-top: 5px;

                                            padding-left: 20px;

                                            float: left;

                                          border: 1px solid #E7E8E9;

                                          border-radius: 3px;

                                          font: 18px "Helvetica", Arial;

                                          background-color: rgb(248, 248, 248);

                                        }

                                        ======================================

                                        Server Script:

                                        =====================================

                                        (function() {

                                          /* populate the 'data' object */

                                          /* e.g., data.table = $sp.getValue('table'); */

                                         

                                         

                                          data.count = [];

                                          data.category = [];

                                          var v_number = 0;

                                         

                                          var kb_count1 = new GlideAggregate("kb_knowledge");

                                          kb_count1.addQuery('workflow_state', 'published');

                                          kb_count1.addAggregate('COUNT');

                                          kb_count1.query();

                                          if(kb_count1.next()){

                                          v_number = kb_count1.getAggregate('COUNT');

                                          }

                                        data.number = v_number;

                                         

                                          //Count Category

                                          var kb_cat = new GlideRecord("kb_category");

                                          kb_cat.addQuery('parent_id', '387b2552ff0131009b20ffffffffffdf');

                                          kb_cat.query();

                                          while(kb_cat.next()){

                                          var v_cat = {};

                                          v_cat.label = kb_cat.getDisplayValue('label');

                                          v_cat.value = kb_cat.getDisplayValue('value');

                                          data.category.push(v_cat);

                                          }

                                         

                                          //Count KB articles

                                          var kb_count = new GlideAggregate("kb_knowledge");

                                          kb_count.addQuery('workflow_state', 'published');

                                          kb_cat.addQuery('kb_knowledge_base', 'a7e8a78bff0221009b20ffffffffff17');

                                          //kb_cat.addQuery('kb_category.parent_id', '387b2552ff0131009b20ffffffffffdf');

                                          kb_count.orderBy('kb_category');

                                          kb_count.addAggregate('COUNT','kb_category');

                                          kb_count.query();

                                          while(kb_count.next()){

                                          var v_count2 = {};

                                          v_count2.category = kb_count.getDisplayValue('kb_category');

                                          v_count2.category_count = kb_count.getAggregate('COUNT','kb_category');

                                          data.count.push(v_count2);

                                          }

                                        })();

                                        ==============================================

                                        Client script:

                                        =====================================

                                        function($scope) {
                                        var c = this;

                                          }

                                        • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                          Shahid Kalaniya

                                          Hi Dave & Chuck,

                                          dave.slusher ctomasi

                                          Can any of you guys please share the updated Widget code from 'Service Portal Part 2, TechNow 29'??

                                          I know its quite late, but it will be very helpful.

                                          By the way, Great session guys!!

                                           

                                          Many thanks!!

                                          • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                            captainbonko

                                            Great video. Very cool tricks.

                                            Are there any resources about routing, modals or navigating tabs?

                                            • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                              nagarjuna reddy

                                              Hi

                                              will you please correct me which line i did wrong

                                               

                                              client script

                                               

                                               

                                               

                                              $scope.putdata($scope.edit_txt.sys_id,{well: $scope.edit_txt.txt});

                                               

                                              $scope.putdata = function (sys_id,data) {

                                              console.log(sys_id);

                                              $http({

                                                       method: 'POST',

                                                       url: '/api/now/table/u_test'+ sys_id,

                                                  headers: {'Content-Type' : "application/json"},

                                                data: data

                                                     });

                                               

                                              i got error ::" Failed to load resource: the server responded with a status of 400 (Bad Request)"  /api/now/table/u_test231bbe390f773200448d4cace1050e70

                                              • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                                Arun Ram

                                                HI ctomasi

                                                 

                                                I am searching for the updated widget code. Can you please let me know where i can find the same.

                                                 

                                                Arun

                                                • Re: Ask the Expert: Service Portal Part 2, TechNow 29
                                                  Arun Ram

                                                  Hi Chuck,

                                                  Updated widget code for Ask the Expert: Service Portal Part 2.

                                                  Apologies, i was not clear in my comments.

                                                   

                                                  Thanks,

                                                  Arun