فهرست
JSOM چیه؟
یکی از راههای مدیریت دیتا توی شیرپوینت، استفاده کردن از JSOM در شیرپوینت برای خوندن، ویرایش، حذف و اضافه کردن دیتاس؛ این کتابخونه به توسعهدهندهها اجازه میده کارای دیگهای مثل تغییر دسترسیها کاربرای مختلف هم انجام بدن.
برای استفاده کردن از JSOM در شیرپوینت فقط نیاز دارید که فایل sp.js رو توی صفحه فراخونی کنید و شروع کنید به کد زدن. برای فراخونی فایل sp.js راههای مختلفی وجود داره؛ مثلاً میشه از وب پارت content editor یا content search استفاده کرد. فرض من اینه که شما توسعهدهنده شیرپوینت هستید و با نحوه کار کردن display templateها توی شیرپوینت آشنایی دارید؛ همچنین به راحتی با HTML و CSS و jQuery کار میکنید.
توی این مقاله من از یه وب پارت content search استفاده کردم؛ البته راههای سرراستتری هم برای استفاده از JSOM در شیرپوینت وجود داره؛ مثلاً توی پست ساختن پورتال سازمانی فارسی از JSOM توی قالب صفحه استفاده کردیم؛ توی 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());
}