استفاده از JSOM در شیرپوینت Using JSOM in SharePoint

آخرین به روزرسانی در 16 آبان 1401
نوشته شده توسط علی خادم
استفاده از JSOM در شیرپوینت

JSOM چیه؟

یکی از راه‌های مدیریت دیتا توی شیرپوینت، استفاده کردن از JSOM برای خوندن، ویرایش، حذف و اضافه کردن دیتاس. برای استفاده کردن از JSOM فقط نیاز دارید که فایل sp.js رو توی صفحه فراخونی کنید و شروع کنید به کد زدن. برای فراخونی فایل sp.js راه‌های مختلفی وجود داره؛ مثلاً می‌شه از وب پارت content editor یا content search استفاده کرد. فرض من اینه که شما توسعه‌دهنده شیرپوینت هستید و با نحوه کار کردن display templateها توی شیرپوینت آشنایی دارید؛ همچنین به راحتی با HTML و CSS و jQuery کار می‌کنید.

توی این مقاله من از یه وب پارت content search استفاده کردم؛ این کار خیلی منطقی‌ترین راه به نظر می‌رسه چون توی display templateهای پیش‌فرض شیرپوینت، روش‌هایی برای فراخونی فایل‌های CSS و JS وجود داره که جلوتر می‌بینید.

JSOM در content search

هر وب پارت content search از دو تا فایل HTML ساخته شده: فایل کنترل و فایل آیتم (این فایل‌ها display template نامیده می‌شن). فایل کنترل فقط یک بار توی مارک‌آپ صفحه تکرار می‌شه و ساختار کلی نتایج سرچ رو مشخص می‌کنه. فایل آیتم، به ازای هر آیتمی که سرچ برگردونه تکرار می‌شه. کدی که من می‌خوام بنویسم لازمه که فقط یک بار در صفحه اجرا بشه، بنابراین یه فایل جاوااسکریپت می‌سازم و توی فایل کنترلم، اون رو فراخونی می‌کنم:

<script>
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Theme Files/css/select2.min.css");
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Theme Files/css/persian-datepicker.min.css");
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Theme Files/js/select2.min.js");
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Theme Files/js/persian-date.min.js");
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Theme Files/js/persian-datepicker.min.js");
     $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Theme Files/js/selectTheDate.js");
</script>

هر چیزی رو می‌تونید با تابع includeLanguageScript فراخونی کنید. توی کد بالا من غیر از چیزایی که توی این پروژه نیاز داشتم، فایل جاوااسکریپتی به اسم selectTheDate فراخونی کردم که قراره توش به روش JSOM کد بنویسم؛ پایین‌تر توی همین فایل کنترل، داخل تگ ul کد HTML پاپ‌آپی رو نوشتم که با فشار دادن یه دکمه قراره باز بشه و اطلاعاتی رو از کاربر دریافت کنه؛ چون از این پاپ‌آپ هم فقط یه دونه توی صفحه نیاز داشتم، این کد رو هم توی فایل کنترل می‌نویسم:

<ul class="cbs-List">

     <!-- pop -->
     <div id="popUpTerms" class="popUpKDM">
          <div class="white popUpContent pa1">

               <!-- date -->
               <div id="dateSelection" class="mt1">
                    <label for="date">انتخاب تاریخ</label>
                    <input type="text" class="date" placeholder="لطفاً انتخاب کنید" />
               </div>
               <!-- date -->

               <!-- actions -->
               <div class="popUpClosed">لغو</div>
               <div class="popUpAccept">ثبت</div>
               <!-- actions -->

          </div>
     </div>
     <!-- pop -->

توی سناریویی که برای نوشتن این مقاله انتخاب کردم، کاربر قراره با فشار دادن یه دکمه، یه پاپ‌آپی رو باز کنه و یه تاریخی رو انتخاب کنه، بعد ما انتخاب اون کاربر رو توی یه لیستِ شیرپوینتی که قبلاً ساختیم ذخیره کنیم؛ برای همین توی کد بالا توی پاپ‌آپ، یه فیلد گذاشتم برای انتخاب تاریخ شمسی.

همون طور که گفتم برای باز شدن پاپ‌آپ کاربر باید یه دکمه‌ای رو فشار بده، اگه فقط یک دکمه برای باز کردن پاپ‌آپ نیاز داشتیم می‌تونستیم همین جا توی همین فایل مارک‌آپ دکمه رو هم بنویسیم، اما من می‌خوام این دکمه به ازای هر آیتمی که سرچ برمی‌گردونه تکرار بشه، برای همینم مارک‌آپِ دکمه رو توی فایل آیتم می‌نویسم:

<a class="btn numGenerator" href="">انتخاب یک تاریخ</a>

خب حالا که خیالم از بابت مارک‌آپ این پاپ‌آپ راحت شد، می‌تونم برم سراغ فایل selectTheDate.js که قراره کار اصلی توش انجام بشه؛ اما قبل از اون باید یاد بگیریم اصلاً JSOM نوشتن چطوریه؟

JSOM در فایل جاوااسکریپت

اولین مرحله اینه که مطمئن بشیم فایل sp.js بارگذاری شده و آماده‌س که ازش استفاده بشه. شیرپوینت یه تابع داره به نام ExecuteOrDelayUntilScriptLoaded که قراره الان ازش استفاده کنیم؛ این تابع چک می‌کنه که اگه یه فایل به خصوص توی صفحه بارگذاری شده باشه، یه تابع دیگه رو اجرا کنه و اگه اون فایل به خصوص بارگذاری نشده باشه، صبر می‌کنه تا اون فایل بارگذاری و آماده بشه:

$(document).ready(function() {
     function stuffToRunAfterSP_JS() {
          console.log('sp.js is loaded now!')
     }
     ExecuteOrDelayUntilScriptLoaded(stuffToRunAfterSP_JS, "sp.js")
})

کاری که این کد انجام می‌ده اینه که صبر می‌کنه تا فایل sp.js توی صفحه کاملاً بارگذاری بشه و بعد تابع stuffToRunAfterSP_JS رو اجرا می‌کنه. حالا همه چی آماده‌س و می‌تونیم شروع کنیم به نوشتن JSOM.

ساختار توابع JSOM

اساساً هر تکه مجزا از کد JSOM که توی هر پروژه نوشته می‌شه و عملیات خاصی رو انجام می‌ده شامل این پنج تا بخش اصلیه:

  • کانتکست ـ آدرس سایت هدف
  • لیست ـ عنوان یا شناسه لیست، در صورت نیاز
  • کوئری ـ کمل کوئری برای دریافت آیتم‌ها، در صورت نیاز
  • عملیات ـ مثلاً حذف یا اضافه یا ویرایش کردن یک آیتم
  • توابع ـ شامل دو تابع که بعد از موفقیت یا شکست عملیات، مراحل بعدی رو مشخص می‌کنن

دریافت اطلاعات با JSOM

با یه مثال خیلی ساده همه چی خیلی واضح‌تر می‌شه: فرض کنیم قراره عنوان همه آیتم‌هایی از یه لیست رو که توشون کلمه «فروش» هست فراخونی کنیم و توی کنسول لاگ کنیم؛ برای این کار باید یه تابع بنویسیم:

$(document).ready(function() {
     function stuffToRunAfterSP_JS() {
          getSaleItems()
     }
     ExecuteOrDelayUntilScriptLoaded(stuffToRunAfterSP_JS, "sp.js")
})

var codingListItems
function getSaleItems() {

        // 1 - ctx
        var clientContext = new SP.ClientContext('https://portal.yourwebsite.com/subsite')

        // 2 - list
        var codingList = clientContext.get_web().get_lists().getByTitle('CodingUnits')

        // 3 - query
        var queryCodingList = new SP.CamlQuery()
        queryCodingList.set_viewXml("<View><Query><Where><Contains><FieldRef Name='Title'/><Value Type='Text'>فروش</Value></Contains></Where></Query></View>")
        codingListItems = codingList.getItems(queryCodingList)
        clientContext.load(codingListItems)

        // 4 - functions
        clientContext.executeQueryAsync(Function.createDelegate(this, onQueryOneSucceededs), Function.createDelegate(this, onQueryOneFaileds))

}
function onQueryOneSucceededs() {
     var codingListEnumerator = codingListItems.getEnumerator()
     var resultCount = codingListItems.get_count()
     if(resultCount > 0) {
          while (codingListEnumerator.moveNext()) {
               var theTitle = codingListEnumerator.get_current().get_item("Title")
               console.log(theTitle)
          }
     } else {
          alert('موردی که شامل کلمه فروش باشد وجود ندارد!')
     }
}
function onQueryOneFaileds(sender, args) {
     alert('Request failed. \nError: ' + args.get_message() + '\nStackTrace: ' + args.get_stackTrace())
}

همون طور که توی کد بالا می‌بینید، تابع اصلی getSaleItems شامل چهار بخشه که من شماره‌گذاری کردم.

بخش اول، کانتکست، در واقع آدرس سایتیه که دارید اطلاعات رو ازش می‌گیرید. اگه سایت مورد نظرتون همون سایتیه که کدتون داره توش اجرا می‌شه، دیگه لازم نیست آدرس سایت رو به عنوان پارامتر توی متد ClientContext وارد کنید.

بخش دوم اسم لیست مورد نظرتونه. من توی این مثال از عنوان لیست استفاده کردم، اما JSOM توابع دیگه‌ای هم برای مشخص کردن لیست هدف داره که مثلاً از شناسه لیست استفاده می‌کنن.

بخش سوم کمل‌کوئریه که روی لیست اعمال شده تا فقط آیتم‌هایی از لیست که توی عنوانشون کلمه «فروش» هست به ما نمایش داده بشه. دقت کنید که توی کمل‌کوئری وقتی داریم از یه ستون شیرپوینتی استفاده می‌کنیم، باید از internal name اون ستون استفاده کنیم. internal name اون اسمیه که اولین بار موقع ساختن یه ستون وارد کردید و هرگز قابل تغییر نیست (اون اسمی که قابل تغییره display name اون ستونه).

بخش چهارم شامل دو تا تابعه که به ترتیب در صورت موفقیت و شکست عملیات، مشخص می‌کنن که قدم‌های بعدی چی قراره باشه.

ساختن آیتم با JSOM

برگردیم به مأموریت اصلی‌مون. قراره کاربر یه تاریخ وارد کنه و ما اون رو توی یه لیست شیرپوینتی ذخیره کنیم. اول باید یه کاری کنیم که فقط وقتی کاربر روی دکمه کلیک کرد پاپ‌آپ باز بشه و همچنین فیلد تاریخ شمسی رو فعال کنیم.

var enDate

$(document).ready(function() {
     function stuffToRunAfterSP_JS() {

          // jalali date field
          $("#popUpTerms input.date").pDatepicker({

               // date format
               format: 'YYYY/MM/DD',
               initialValue: false,

               // set year
               onSelect: function(unix){

                    // the selected date
                    var date = new Date(unix).toLocaleDateString('fa-IR')

                    // the english date
                    enDate = new Date(unix)

            }

        })
          
          // show pop up
          $('a.numGenerator').on('click', function(event) {

               //show pop up
               $('#popUpTerms').show()
            
               // actions
               $('#popUpTerms .popUpAccept').show();
               $('#popUpTerms .popUpAccept').on('click', function(){
                    // create the item
               })
               $('.popUpClosed').show();
               $('.popUpClosed').on('click', function(){
                    $('#popUpTerms').hide();
               })

        })

     }
     ExecuteOrDelayUntilScriptLoaded(stuffToRunAfterSP_JS, "sp.js")
})

توی کد بالا وقتی کاربر پاپ‌آپ رو باز کنه و تاریخ رو انتخاب کنه، تاریخ انتخاب‌شده توی متغیر enDate قرار می‌گیره؛ جلوتر می‌بینید که برای مشخص کردن تاریخی که قراره توی آیتم جدید ذخیره کنیم از همین متغیر استفاده می‌کنیم. یه خرده استایل هم اضافه کردم که پاپ‌آپ از نظر ظاهری قابل‌قبول باشه:

/* popup */
.popUpKDM {
     display: none;
     background: #00000070;
     position: fixed;
     width: 100vw;
     height: 100vh;
     right: 0;
     top: 0;
     z-index: 999;
}
.popUpContent {
     overflow: hidden;
     width: max-content;
     min-width: 25%;
     left: 0;
     right: 0;
     top: 50%;
     transform: translate(0px, -50%);
     margin: auto;
     position: absolute;
     height: max-content;
     font-size: 1.25em;
     border-radius: .5em;
}
.popUpAccept, .popUpCancel, .popUpClosed {    
     background: #a2ffa2;
     padding-left: 1em;
     padding-right: 1em;
     width: max-content;
     float: left;
     margin-top: 1em;
     border-radius: .25em;
     height: 2.5em;
     line-height: 2.5em;
     cursor: pointer;
} 
.popUpClosed {    
     background: #ffdda8;
}
.popUpCancel {
     background: #ffcaca;
     margin-left: .5em;
}
/* popup */

بعد از انتخاب تاریخ و فشار دادن دکمه ثبت، باید تابع JSOM فراخونی بشه و یه آیتم توی لیستی که ما بهش می‌گیم ثبت کنه. تابع JSOM رو بر اساس ساختاری که بالاتر توضیح دادم می‌نویسیم:

function createItem() {

     // 1 - ctx
     var clientContext = new SP.ClientContext('https://portal.yourwebsite.com/subsite')

     // 2 - list
     var oList = clientContext.get_web().get_lists().getByTitle("The List Name")

     // 3 - create
     var oListItemCreationInformation = new SP.ListItemCreationInformation()
     var oListItem = oList.addItem(oListItemCreationInformation)
     oListItem.set_item('Title', 'تست ثبت تاریخ')
     oListItem.set_item('SPSDate', enDate)
     oListItem.update()
     clientContext.load(oListItem)
        
     // 4 - functions
     clientContext.executeQueryAsync(andicatorOnSuccess, andicatorOnFail)

}
function andicatorOnSuccess() {
     alert('یک آیتم جدید ساخته شد')
}
function andicatorOnFail(sender, args) {
     alert('خطا در مرحله ساختن مورد در اندیکاتور')
     alert('Failed' + args.get_message() + '\n' + args.get_stackTrace());
}

این تابع هم مثل تابع قبلی شامل چهار بخشه که شماره‌گذاری کردم.

بخش اول که آدرس سایته. بخش دوم اسم لیستیه که آیتم قراره توش ساخته بشه. توی این تابع کمل‌کوئری نداریم و بخش سوم شامل متدهای مربوط به ساختن آیتم جدیده؛ مثل کمل‌کوئری، این جا هم وقتی قراره از یه ستون شیرپوینتی نام ببریم، باید از internal name اون ستون استفاده کنیم. بخش چهارم هم شامل دو تا تابعه که به ترتیب در صورت موفقیت و شکست عملیات، مشخص می‌کنن که قدم‌های بعدی چی قراره باشه.

این دو تا مثال ساده از نحوه کار کردن JSOM توی شیرپوینت بود. در نهایت کدی که برای اضافه کردن یه آیتم به لیست استفاده می‌شه اینه:

var enDate

$(document).ready(function() {
     function stuffToRunAfterSP_JS() {

          // jalali date field
          $("#popUpTerms input.date").pDatepicker({

               // date format
               format: 'YYYY/MM/DD',
               initialValue: false,

               // set year
               onSelect: function(unix){

                    // the selected date
                    var date = new Date(unix).toLocaleDateString('fa-IR')

                    // the english date
                    enDate = new Date(unix)

            }

        })
          
          // show pop up
          $('a.numGenerator').on('click', function(event) {

               //show pop up
               $('#popUpTerms').show()
            
               // actions
               $('#popUpTerms .popUpAccept').show();
               $('#popUpTerms .popUpAccept').on('click', function(){
                    createItem()
               })
               $('.popUpClosed').show();
               $('.popUpClosed').on('click', function(){
                    $('#popUpTerms').hide();
               })

        })

     }
     ExecuteOrDelayUntilScriptLoaded(stuffToRunAfterSP_JS, "sp.js")
})

function createItem() {

     // 1 - ctx
     var clientContext = new SP.ClientContext('https://portal.yourwebsite.com/subsite')

     // 2 - list
     var oList = clientContext.get_web().get_lists().getByTitle("RecAndicator")

     // 3 - create
     var oListItemCreationInformation = new SP.ListItemCreationInformation()
     var oListItem = oList.addItem(oListItemCreationInformation)
     oListItem.set_item('Title', 'تست ثبت تاریخ')
     oListItem.set_item('SPSDate', enDate)
     oListItem.update()
     clientContext.load(oListItem)
        
     // 4 - functions
     clientContext.executeQueryAsync(andicatorOnSuccess, andicatorOnFail)

}
function andicatorOnSuccess() {
     alert('یک آیتم جدید ساخته شد')
}
function andicatorOnFail(sender, args) {
     alert('خطا در مرحله ساختن مورد در اندیکاتور')
     alert('Failed' + args.get_message() + '\n' + args.get_stackTrace());
}

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *