Fetch and save Sitecore Item in SPEAK 2 using Sitecore.Services.Client

testapppage

Hello guys, yet another post about SPEAK ๐Ÿ™‚
In this medium small post I would like to share with you how I work with Sitecore items in SPEAK.

Let’s say you need to retrieve a Sitecore item, modify it and update it.
In this example the Sitecore item is exposed in an url, like this:

https://somehost.com/sitecore/client/MyApp/Applications/TestApp/TestAppPage?id=7E4CA53A-59AA-4C08-9EEF-71DDF66E8A8E&database=master&language=en&version=1

This will be a simple page containing two text boxes and a save button(See above)
Here is the Design Layout for the page:
tasklayout
I really like the Grid rendering and guess what it’s responsive friendly ๐Ÿ™‚

To get an item I do something like this:

GetTestData: function (callback) {

	var self = this;
	var testObject = {};
	testObject["id"] = Sitecore.Speak.utils.url.parameterByName("id");
	testObject["language"] = Sitecore.Speak.utils.url.parameterByName("language");
	testObject["version"] = Sitecore.Speak.utils.url.parameterByName("version");
	testObject["database"] = Sitecore.Speak.utils.url.parameterByName("database");
	testObject["databaseUri"] = new _sc.Definitions.Data.DatabaseUri(testObject["database"]);
	testObject["itemUri"] = new _sc.Definitions.Data
		.ItemUri(testObject["databaseUri"], testObject["id"]);
	testObject["itemVersionUri"] = new _sc.Definitions.Data
		.ItemVersionUri(testObject["itemUri"],
			testObject["language"],
			parseInt(testObject["version"]));

	var db = new _sc.Definitions.Data.Database(testObject["databaseUri"]);

	db.getItem(testObject["itemVersionUri"],
		function (item) {

			testObject["itemName"] = item.itemName;
			testObject["itemDisplayname"] = item.$displayName;

			var testHeaderField = item.getFieldById(self.Constants.TestHeaderFieldId);
			testObject["itemFieldTestHeader"] = testHeaderField.value;

			var testDescriptionField = item.getFieldById(self.Constants.TestDescriptionFieldId);
			testObject["itemFieldTestDescription"] = testDescriptionField.value;

			callback(testObject);

		});


}

The reason for the callback function is because of db.getItem. When the method has retrieved the Sitecore item I’ll put the data in a JSON object.
The Sitecore.Speak.utils.url.parameterByName is indeed handy ๐Ÿ™‚
(I’m not using Sitecore.Services.Client here)

To call the GetTestData method:

BindTestData: function () {
	var self = this;

	self.GetTestData(function (testObject) {
		self.TestData = testObject;

		//Do some binding stuff to the controls on your Speak layout page
		self.MyHeaderTextBox.Value = self.TestData.itemFieldTestHeader;
		self.MyDescriptionTextBox.Value = self.TestData.itemFieldTestDescription;
	});

}

Here we will bind/set the data to the text boxes.
(self.TestData is just a container)

To update a Sitecore item we will use Sitecore.Services.Client. Thanks to Kevin Obee’s great “living” documentation, http://docs.itemserviceapi.apiary.io, he made it so much easier to understand how it works.
There is also a great post that describes the differences between Sitecore Item Web API and Sitecore.Services.Client – What is Sitecore.Services.Client?

Here is how the we update the Sitecore item using Sitecore.Services.Client

UpdateSitecoreData: function (callback) {
	var self = this;

	var request = new XMLHttpRequest();

	var url = self.StringFormat("/sitecore/api/ssc/item/{0}?database={1}&language={2}&version={3}",
		self.TestData.id,
		self.TestData.database,
		self.TestData.language,
		self.TestData.version);

	request.open("PATCH", url);

	request.setRequestHeader('Content-Type', 'application/json');

	var body = {
		'TestHeader': self.TestData.itemFieldTestHeader,
		'TestDescription': self.TestData.itemFieldTestDescription
	};

	request.send(JSON.stringify(body));

	request.onreadystatechange = function () {

		return callback(this.readyState, this.status, this.responseText);

	};
}

Again I’m using a callback, since we need to wait for the response if the save was successful or not. TestHeader and TestDescription are the field names of the Sitecore item.

Another thing, if you would get the forbidden page (You do not have permission to view this directory or page) when using the Sitecore.Services.Client. That means you probably have to take a look at the security policy settings in Sitecore.Services.Client.config. Find the setting that works best for you.

And here we call UpdateSitecoreData:

SaveTestData: function () {
	var self = this;

	//Get the data from the text boxes 
	self.TestData.itemFieldTestHeader = self.MyHeaderTextBox.Value;
	self.TestData.itemFieldTestDescription = self.MyDescriptionTextBox.Value;
	
	self.UpdateSitecoreData(function (readyState, status, responseText) {
		//Failure
		if (readyState === 4 && (this.status === 404 || status === 500)) {
			self.StatusAlertConfirmationDialog["HeaderText"] = "Save - error";
			self.StatusAlertConfirmationDialog["Title"] = "An error occurred while saving, please contact support";
			self.StatusAlertConfirmationDialog["IconType"] = "error";
			self.StatusAlertConfirmationDialog["Message"] = responseText;
			self.StatusAlertConfirmationDialog.show();
			self.StatusAlertConfirmationDialog.IsVisible = true;

		}

		//Success
		if (readyState === 4 && this.status !== 404 && status !== 500) {
			self.BindTestData();
		}


	});

}

If you succeed with the update we will “rebind” the data by calling BindTestData, if not we will show a StatusAlertConfirmationDialog(ConfirmationDialog).

Here is the full PageCode file:

(function (Speak) {

	Speak.pageCode({
		initialized: function () {
			console.log("Start TestAppPage");
			var self = this;

			self.SaveTestButton.on("click", self.ConfirmSave, this);

			self.UpdateTestDataConfirmationDialog.on("close",
				function (data) {

					if (data === "ok") {

						self.SaveSearch();
				
					}
                    self.UpdateTestDataConfirmationDialog.IsVisible = false;
				},
				this);	

			self.BindTestData();


		},
		ConfirmSave: function () {
			var self = this;
			self.UpdateTestDataConfirmationDialog.show();
			self.UpdateTestDataConfirmationDialog.IsVisible = true;
		},
		BindTestData: function () {
			var self = this;

			self.GetTestData(function (testObject) {
				self.TestData = testObject;

				//Do some binding stuff to the controls on your Speak layot page
                self.MyHeaderTextBox.Value = self.TestData.itemFieldTestHeader;
                self.MyDescriptionTextBox.Value = self.TestData.itemFieldTestDescription;
			});


		},
		GetTestData: function (callback) {

			var self = this;

			var testObject = {};
			testObject["id"] = Sitecore.Speak.utils.url.parameterByName("id");
			testObject["language"] = Sitecore.Speak.utils.url.parameterByName("language");
			testObject["version"] = Sitecore.Speak.utils.url.parameterByName("version");
			testObject["database"] = Sitecore.Speak.utils.url.parameterByName("database");
			testObject["databaseUri"] = new _sc.Definitions.Data.DatabaseUri(testObject["database"]);
			testObject["itemUri"] = new _sc.Definitions.Data
				.ItemUri(testObject["databaseUri"], testObject["id"]);
			testObject["itemVersionUri"] = new _sc.Definitions.Data
				.ItemVersionUri(testObject["itemUri"],
					testObject["language"],
					parseInt(testObject["version"]));

			var db = new _sc.Definitions.Data.Database(testObject["databaseUri"]);

			db.getItem(testObject["itemVersionUri"],
				function (item) {

					testObject["itemName"] = item.itemName;
					testObject["itemDisplayname"] = item.$displayName;

					var testHeaderField = item.getFieldById(self.Constants.TestHeaderFieldId);
					testObject["itemFieldTestHeader"] = testHeaderField.value;

					var testDescriptionField = item.getFieldById(self.Constants.TestDescriptionFieldId);
					testObject["itemFieldTestDescription"] = testDescriptionField.value;

					callback(testObject);

				});


		},
		Constants: {
			"TestHeaderFieldId": "{3699A67C-A4BC-486D-9A37-9E4554AE46CA}",
			"TestDescriptionFieldId": "{E85C0CA0-75F2-4FB7-B2B5-03D8B97EBCCA}"
		},
		TestData: function () {
			var content;

			return content;
		},
		SaveTestData: function () {
			var self = this;

			//Get the data from the textboxes 
			self.TestData.itemFieldTestHeader = self.MyHeaderTextBox.Value;
			self.TestData.itemFieldTestDescription = self.MyDescriptionTextBox.Value;
			
			self.UpdateSitecoreData(function (readyState, status, responseText) {
				//Failure
				if (readyState === 4 && (this.status === 404 || status === 500)) {
					self.StatusAlertConfirmationDialog["HeaderText"] = "Save - error";
					self.StatusAlertConfirmationDialog["Title"] = "An error occurred while saving, please contact support";
					self.StatusAlertConfirmationDialog["IconType"] = "error";
					self.StatusAlertConfirmationDialog["Message"] = responseText;
					self.StatusAlertConfirmationDialog.show();
					self.StatusAlertConfirmationDialog.IsVisible = true;

				}

				//Success
				if (readyState === 4 && this.status !== 404 && status !== 500) {
					self.BindTestData();
				}


			});


		},
		UpdateSitecoreData: function (callback) {
			var self = this;

			var request = new XMLHttpRequest();

			var url = self.StringFormat("/sitecore/api/ssc/item/{0}?database={1}&language={2}&version={3}",
				self.TestData.id,
				self.TestData.database,
				self.TestData.language,
				self.TestData.version);

			request.open("PATCH", url);

			request.setRequestHeader('Content-Type', 'application/json');

			var body = {
				'TestHeader': self.TestData.itemFieldTestHeader,
				'TestDescription': self.TestData.itemFieldTestDescription
			};

			request.send(JSON.stringify(body));

			request.onreadystatechange = function () {

				return callback(this.readyState, this.status, this.responseText);

			};
		},
		StringFormat: function () {
			var s = arguments[0];
			for (var i = 0; i < arguments.length - 1; i++) {
				var reg = new RegExp("\\{" + i + "\\}", "gm");
				s = s.replace(reg, arguments[i + 1]);
			}
			return s;
		}
		
	});
})(Sitecore.Speak);

If you noticed there is a call to ConfirmSave when the Save button is clicked which will popup a ConfirmationDialog.

ConfirmSave: function () {
	var self = this;
	self.UpdateTestDataConfirmationDialog.show();
	self.UpdateTestDataConfirmationDialog.IsVisible = true;
}

If you are wondering about the self.UpdateTestDataConfirmationDialog.IsVisible = true, yes the show() method is enough to pop up the dialog. But I need to know that the dialog is visible, that’s why I’m using the IsVisible attribute.

Finally in the initialized function we are listening to the UpdateTestDataConfirmationDialog’s close event. If OK button is clicked we will call the SaveSearch.

self.UpdateTestDataConfirmationDialog.on("close",
function (data) {

	if (data === "ok") {

		self.SaveSearch();
 
	}
	self.UpdateTestDataConfirmationDialog.IsVisible = false;
},
this);

Thatโ€™s it and keep doing some good SPEAK stuff out there.

Thatโ€™s all for now folks ๐Ÿ™‚


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.