Read content of SP.File object as text using JSOM - sharepoint-2013

as the title suggests, I am trying to read the contents of a simple text file using JSOM. I am using a Sharepoint-hosted addin for this, the file I am trying to read resides on the host web in a document library.
Here's my JS code:
function printAllListNamesFromHostWeb() {
context = new SP.ClientContext(appweburl);
factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
context.set_webRequestExecutorFactory(factory);
appContextSite = new SP.AppContextSite(context, hostweburl);
this.web = appContextSite.get_web();
documentslist = this.web.get_lists().getByTitle('Documents');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><ViewFields><FieldRef Name="Name"/></ViewFields></View>');
listitems = documentslist.getItems(camlQuery);
context.load(listitems, 'Include(File,FileRef)');
context.executeQueryAsync(
Function.createDelegate(this, successHandler),
Function.createDelegate(this, errorHandler)
);
function successHandler() {
var enumerator = listitems.getEnumerator();
while (enumerator.moveNext()) {
var results = enumerator.get_current();
var file = results.get_file();
//Don't know how to get this to work...
var fr = new FileReader();
fr.readAsText(file.get);
}
}
function errorHandler(sender, args) {
console.log('Could not complete cross-domain call: ' + args.get_message());
}
}
However, in my succes callback function, I don't know how I can extract the contents of the SP.File object. I tried using the FileReader object from HTML5 API but I couldn't figure out how to convert the SP.File object to a blob.
Can anybody give me a push here?

Once file url is determined file content could be loaded from the server using a regular HTTP GET request (e.g. using jQuery.get() function)
Example
The example demonstrates how to retrieve the list of files in library and then download files content
loadItems("Documents",
function(items) {
var promises = $.map(items.get_data(),function(item){
return getFileContent(item.get_item('FileRef'));
});
$.when.apply($, promises)
.then(function(content) {
console.log("Done");
//print files content
$.each(arguments, function (idx, args) {
console.log(args[0])
});
},function(e) {
console.log("Failed");
});
},
function(sender,args){
console.log(args.get_message());
}
);
where
function loadItems(listTitle,success,error){
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var list = web.get_lists().getByTitle(listTitle);
var items = list.getItems(createAllFilesQuery());
ctx.load(items, 'Include(File,FileRef)');
ctx.executeQueryAsync(
function() {
success(items);
},
error);
}
function createAllFilesQuery(){
var qry = new SP.CamlQuery();
qry.set_viewXml('<View Scope="RecursiveAll"><Query><Where><Eq><FieldRef Name="FSObjType" /><Value Type="Integer">0</Value></Eq></Where></Query></View>');
return qry;
}
function getFileContent(fileUrl){
return $.ajax({
url: fileUrl,
type: "GET"
});
}

Related

How to get current filters from PowerBi embedded export report

I am using powerbi embedded and I would like an export button similar to the one used on powerbi.com, that asks if you want to apply the current filters or not.
How can I get the current filters in javaScript in such a way that these can be passed to the back end, or to the javascript api to generate a PDF?
I am using the following code to generate the PDF currently, I just don't know how to get the current configuration current filters and current page selected in javaScript
public PowerBiExportViewModel CreateExport(Guid groupId,
Guid reportId,
IEnumerable<PowerBiReportPage> reportPages,
FileFormat fileFormat,
string urlFilter,
TimeSpan timeOut)
{
var errorMessage = string.Empty;
Stream stream = null;
var fileSuffix = string.Empty;
var securityToken = GetAccessToken();
using (var client = new PowerBIClient(new Uri(BaseAddress), new TokenCredentials(securityToken, "Bearer")))
{
var powerBiReportExportConfiguration = new PowerBIReportExportConfiguration
{
Settings = new ExportReportSettings
{
Locale = "en-gb",
IncludeHiddenPages = false
},
Pages = reportPages?.Select(pn => new ExportReportPage { PageName = pn.Name }).ToList(),
ReportLevelFilters = !string.IsNullOrEmpty(urlFilter) ? new List<ExportFilter>() { new ExportFilter(urlFilter) } : null,
};
var exportRequest = new ExportReportRequest
{
Format = fileFormat,
PowerBIReportConfiguration = powerBiReportExportConfiguration
};
var export = client.Reports.ExportToFileInGroupAsync(groupId, reportId, exportRequest).Result;
You can go to PowerBi playground and play around with their sample report. Next to "Embed" button you have "Interact" and option to get filters. In response you get JSON with filters. If you are too lazy to go there, here is the code it created for me
// Get a reference to the embedded report HTML element
var embedContainer = $('#embedContainer')[0];
// Get a reference to the embedded report.
report = powerbi.get(embedContainer);
// Get the filters applied to the report.
try {
const filters = await report.getFilters();
Log.log(filters);
}
catch (errors) {
Log.log(errors);
}

Can not pass a list of strings to a Web API endpoint. Why?

Can not pass a list of strings to a Web API endpoint. Why?
Here is my controller:
[Route("[controller]")]
[ApiController]
public class MyController
{
[HttpPost("foo")]
public string MyMethod(List<string> strs)
{
return "foo";
}
}
Here is how I am trying to call it:
var strs = new List<string> { "bar" };
var json = JsonConvert.SerializeObject(strs);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpCliet.PostAsync("/My/foo", content);
Before calling the endpoint I place a breakpoint on the return "foo"; line. Once the breakpoint is hit the strs list inside the MyController.MyMethod is empty. The strs is not null, but it contains no elements. While my intentions and expectations are to see the strs containing one element, i.e. the string "bar".
I am using the ASP.NET Core 2.2 in project where I create and use the HttpClient. And I am using the same ASP.NET Core 2.2 in project where I have the endpoint.
I am not sure what is wrong here. I have checked a few sources. E.g. the following:
C# HTTP post , how to post with List<XX> parameter?
https://carldesouza.com/httpclient-getasync-postasync-sendasync-c/
https://blog.jayway.com/2012/03/13/httpclient-makes-get-and-post-very-simple/
And I can not find what I am missing according to those resources.
UPDATE
The following call works for me as expected:
var json = JsonConvert.SerializeObject(string.Empty);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await server.CreateClient().PostAsync("/My/foo?strs=bar", content);
Maybe someone knows why the parameters in my case are read from the query string only, but not from body?
You can change your url to a full url in client.PostAsync.Here is a demo worked:
Api(localhost:44379):
WeatherForecastController:
[HttpPost("foo")]
public string MyMethod(List<string> strs)
{
return "foo";
}
Call(localhost:44326):
public async Task<IActionResult> CheckAsync() {
HttpClient client = new HttpClient();
var strs = new List<string> { "bar","bar1","bar2" };
var json = JsonConvert.SerializeObject(strs);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://localhost:44379/WeatherForecast/foo", content);
return Ok(response);
}
result:

Famo.us: Slideshow tutorial with the Picasa API is out of date

I've been working on the famo.us Slideshow tutorial and realised that the API is no longer working.
Any ideas how can I still make this to work without the Picasa API?
You can keep the API by using the following code for SlideData.js
You can make it work by creating the objects returned by the url + parameters below and returning them as the JSON object if you do not want to use the API.
define(function(require, exports, module) {
var SlideData = {
picasaUrl: 'https://picasaweb.google.com/data/feed/api/all',
queryParams: '?kind=photo&q=puppy&max-results=5&imgmax=720&alt=json',
defaultImage: 'https://lh4.googleusercontent.com/-Roszbra0TlI/VB-fE83NAXI/AAAAAAAAACU/ITmhyZMHZrk/s720/cute%252520looking%252520white%252520and%252520black%252520french%252520Bulldog%252520Puppy.jpg'
};
SlideData.getUrl = function() {
return SlideData.picasaUrl + SlideData.queryParams;
};
SlideData.parse = function(data) {
var urls = [];
data = JSON.parse(data);
var entries = data.feed.entry;
for (var i = 0; i < entries.length; i++) {
var media = entries[i].media$group;
urls.push(media.media$content[0].url);
}
return urls;
};
module.exports = SlideData;
});

How do I return data to a template with Knockout and Requirejs modules?

I'm having a difficult time returning data from a module using RequireJS and Knockout to populate my markup for my single page app. Knockout can't seem to find my data binding observables.
I'm trying to keep each view in a separate js file, but I'm failing to identify where I've gone wrong. Here's what I have so far:
/app/app.js
define(function(require) {
require('simrou');
var $ = require('jQuery'),
ko = require('knockout'),
videoView = require('videoView');
var init = function() {
var viewModel = function() {
var self = this;
self.currentPage = ko.observable();
self.videoView = new videoView();
}
var view = new viewModel();
ko.applyBindings( view );
_router = new Simrou({
'/video/:id': [ view.videoView.getVideo ]
});
_router.start();
};
return {
init: init
};
});
/app/videoView.js
define(function(require) {
"use strict";
var $ = require('jQuery'),
ko = require('knockout');
return function() {
var self = this;
self.currentPage = ko.observable( 'showVideo' );
self.currentVideo = ko.observable();
self.videoData = ko.observableArray([]);
self.videoList = ko.observableArray([]);
var getVideo = function( event, params ) {
// ajax pseudo code
$.ajax({});
self.videoData( dataFromAjaxCall );
}
return {
getVideo: getVideo
};
};
});
index.html
When I browse to /#/video/14 I receive the following error:
Uncaught ReferenceError: Unable to parse bindings.
Bindings value: attr: { 'data-video-id': videoData().id }
Message: videoData is not defined
Here's the markup:
<section id="showVideo" data-bind="fadeVisible: currentPage()=='showVideo', with: $root">
<div class="video" data-bind="attr: { 'data-video-id': videoData().id }></div>
</section>
Like I said, I'm trying to keep each view separated, but I would love some enlightenment on what I'm doing wrong, or if this is even possible? Is there a better more efficient way?
videoData is a property of $root.videoView, not of the root model (the one you passed to applyBindings). It's also an observableArray, so videoData() is just a plain array and even if you get the context right, you won't be able to access its id property, since, being an array, it doesn't have.named properties.

Upload an image to Drupal 7 / Services 3 from Titanium?

This must be close but I can't figure out what's causing the error.
In my Titanium app, I have a Webview with a canvas element and this code:
function getImageData() {
return canvas.toDataURL('image/png');
}
I am moving that data to the Titanium app like this:
var imageBase64data = webview.evalJS('getImageData()')
The data looks good starting with "data:image/png;base64,"...
Then in Titanium, I have a logged-in drupal session and call this function:
function uploadImage(imageBase64data, callback) {
var url = REST_PATH + "file.json";
var file = {
filename: utils.createRandomString() + ".png",
file: imageBase64data
// uid: Titanium.App.Properties.getString("userUid"),
// filesize: ""+Titanium.Utils.base64decode(imageBase64data).length,
};
var xhr = Titanium.Network.createHTTPClient({timeout: 30000});
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
var authString = Titanium.App.Properties.getString("userSessionName")+'='+Titanium.App.Properties.getString("userSessionId");
xhr.setRequestHeader("Cookie", authString);
xhr.onload = function() {
if(xhr.status == 200) {
var response = xhr.responseText;
callback(response);
}
};
xhr.onerror = function(e) {
alert("There was an error: " + e.error);
Ti.API.info(JSON.stringify(this));
};
xhr.open("POST", url);
xhr.send(file);
}
xhr.onerror is being called with e.error = "undefined"
The trace looks like this:
{
"responseData":{},
"readyState":4,
"connected":true,"UNSENT":0,"DONE":4,"HEADERS_RECEIVED":2,"OPENED":1,"LOADING":3,
"responseText":null,"status":406
}
I think authentication is working because I was previously getting a "need authentication" error until I added the Cookie header.
That was with the installation provided by Drupanium. I just did a fresh Drupal and fresh Services 3 install and my file is uploading nicely.