tag:blogger.com,1999:blog-57607039667758040122024-03-13T17:38:44.561-07:00Share The LearningDiscoveries, glimpses, insights, and links to useful stuff about SharePoint and software development in general.whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.comBlogger153125tag:blogger.com,1999:blog-5760703966775804012.post-84531351253982391442016-09-11T20:46:00.002-07:002016-09-11T20:46:42.131-07:00yo @microsoft/sharepoint fails for SPFx Dev Preview in VIsual Studio CodeThe <a href="https://github.com/SharePoint/sp-dev-docs/wiki/HelloWorld-WebPart">Hello World tutorial</a> which describes the use of the Yeoman template to create a SharePoint Framework web part in Visual Studio Code suggests that the template should be installed globally. <br />
<br />
When I follow these instructions, I am unable to create the project using yo @microsoft/sharepoint - that call gives the message:<br />
<br />
<pre>Error @microsoft/sharepoint
You don't seem to have a generator with the name @microsoft/sharepoint installed....
</pre>
<br />
I have found that installing the template locally (without the --g parameter) allows me to call the templatewhats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-50068960080773052632016-08-08T21:14:00.003-07:002016-08-08T21:44:47.954-07:00The Common Data Model - yet another back-end data store?Recently integrated into the PowerApps preview (used to be called a beta, I believe?) is an option on the left navigation termed "Entities". Click on that and a new Common Data Model ("CDM") database will be created for you. <br />
<br />
This is a new type of business database being offered by Microsoft for use in delivering business applications (see <a href="https://businessplatform.microsoft.com/">https://businessplatform.microsoft.com</a> for an introduction to this initiative). Currently its purpose in the mix of cloud services is to act as a data store for apps built with PowerApps, Power BI and Flow. It comes pre-configured with commonly-used data types known as Entities, such as "customer" and "purchase order". These entities each contain sets of fields for relevant data. The PowerApps web studio lists all these entities, and offers a link to interact with each entity in Excel - this allows data in the entity to be viewed and updated. This pre-configuration, and the ability to manage these entities, effectively places the CDM one abstraction level above SQL Server.<br />
<br />
Seems as though SharePoint is destined to become a second-class data store when it comes to PowerApps. But that's not such a Bad Thing really - SharePoint lists were never intended to be used to model and contain relational data. I like the idea that these new entities and the Common Data Model hide the management of columns, tables, views and stored procedures which are necessary when using SQL Server. The <a href="https://powerapps.microsoft.com/en-us/blog/announcing-powerapps-common-data-model/">original announcement</a> discusses the fact that the CDM is built upon Azure key capabilities, so scaling (and hopefully performance) are ensured out of the box. <br />
<br />
Losing control over data access methods could be a cause for concern for developers, as could the potential for pre-configured data relationships which may not represent a company's view of the world. But the idea of allowing organizations to replace the mix of Excel spreadsheets, Access databases and other sundry data stores that often contain key business data & processes has got to be worth considering! It's going to be interesting to see whether this latest concept has legs....whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-83949084201050420272016-07-28T19:43:00.002-07:002016-07-28T20:26:39.879-07:00Expose an ES2015 Module as a Global with Browserify (react-addons-update)Calling the React setState() method within TypeScript in Visual Studio Code requires that all properties of the state object are set in the parameter to that method. That was proving a nuisance when there are a few state properties, so I decided to use the update addon available in React - that allows for a much simpler command such as
<br />
<pre class="brush: jscript">let newState = update(this.state, {
message: {$set: "Success!"}
});
this.setState(newState);
</pre>
Adding the react-addons-update module without any other changes to the build operations in gulp caused the content of that addon to be included in the bundled JS when processed by browserify. <br />
<br />
That additional content can be excluded from the bundled JS by these adjustments:
<br />
<ol>
<li>Use the "external()" method on browserify to remove it from the bundle
<pre class="brush: jscript"> let bundler = browserify({
entries: config.rootJS,
debug: true //This provides sourcemapping
}) //Initialising browserify
.external(['react', 'react-addons-update', 'react-dom', 'react-router']);
</pre>
</li>
<li>Add a shim entry in the package.json file to map a global name to the addon
<pre class="brush: jscript"> "browserify-shim": {
"react": "global:React",
"react-addons-update": "global:React_Addons_Update",
"react-dom": "global:ReactDOM",
"react-router": "global:ReactRouter"
}
</pre>
</li>
<li>Create an additional JavaScript file containing the ES2015 addon code transpiled to E5</li>
</ol>
That last stage required a new gulp task, passing the file "update.js" file from the React source to browserify.
<br />
<br />
However, that new bundled file for the addon did not expose a global name that could be used within my custom bundle. The key to exposing this global name proved to be adding the "standalone" parameter in the browserify call (line 6 in the code below).
<br />
<pre class="brush: jscript">gulp.task('packageReactAddons', () => {
let bundler = browserify({
entries: 'node_modules/react/lib/update.js',
debug: false,
standalone: 'React_Addons_Update'
});
return bundler.bundle()
.on('error', console.error.bind(console))
.pipe(source('react_addons_update.js')) // Pass desired output file name to vinyl-source-stream
.pipe(gulp.dest(config.librariesOutputPath)); // Destination for the bundle
})
</pre>
After uploading the resulting JS file to a page, I could see the object named "React_Addons_Update" in the global name space of the page. Yeah!
whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-30238201229803899292016-07-26T14:19:00.002-07:002016-07-27T19:28:10.696-07:00Using a JavaScript Library in TypeScript Modules - the D.TS FIle<div style="background-color: #e0e0e0; border: 1px solid rgb(255, 102, 51); margin: 10px; padding: 10px;">
<em style="font-weight: bold;">Update</em> - After restructuring the JavaScript code to separate views from components, as per the <a href="https://css-tricks.com/learning-react-container-components/" title="Leveling up with React - Container Components">great article</a> by Brad Westfall, I found that the local custom declaration file no longer satisfied the compiler. The reason is that the views and container components are placed in separate folders, which breaks the relative module path references. For the sake of expediency, I have resorted to moving the custom declaration file into the SPScript node_module folder. Not great, I know, but it works and so will do in the meantime.<br />
<br />
If you are needing to hand-craft your own d.ts files, have a look at <a href="https://www.stevefenton.co.uk/2013/01/complex-typescript-definitions-made-easy/">Complex Typescript Definitions Made Easy</a> by Steve Fenton. You'll be glad you did!</div>
The JavaScript library <a href="https://github.com/DroopyTersen/spscript" title="SPScript in Github">SPScript</a> simplifies REST calls to SharePoint from the client by wrapping the AJAX requests in higher level abstractions. Seemed a useful library for my trials with TypeScript, React and D3 in presenting SharePoint data, so I added it to my source code in Visual Studio Code, and imported the file into my module App.ts.
<br />
<h3 style="margin-bottom: 0px; margin-top: 1em;">
Issue - Cannot Find Module SPScript</h3>
Its not that simple in Typescript. First issue to correct is the red squiggly that appeared under SPScript in the following statement:
<br />
<pre class="brush: jscript">import SPScript from "SPScript";
</pre>
This error notification from the editor environment indicates that TypeScript cannot locate a module that matches that import statement. Looking through the <a href="https://www.typescriptlang.org/docs/handbook/module-resolution.html">module resolution</a> notes in the online TypeScript handbook shows the locations and files which the compiler will check for the sought module (see the section titled "How TypeScript resolves modules" on that page for the details). SPScript is provided as a plain JavaScript library, without .TS or .D.TS files. So none of the files expected by the node name resolution would be found.<br />
<br />
To correct this, it was necessary to add a file at one of those locations. Rather than make any adjustments to the SPScript node module (risky!), I added the declaration file SPScript.d.ts in the same folder as the App.ts file, and added an export statement to that new file to set this file as a module.<br />
<br />
<em>A note on Visual Studio Code</em> - I have noticed that VS Code is sometimes slow to indicate that errors are corrected. In this case, the red squiggly did not disappear, even with the new file in place. If you close and reopen the file with the issue (in my case, App.ts) then the error was gone when the file reopened!
<br />
<h3 style="margin-bottom: 0px; margin-top: 1em;">
Issue - What to Include in the Declaration File?</h3>
The call I wanted to make using SPScript is as follows:
<br />
<pre class="brush: jscript"> const dao = new SPScript.RestDao(_spPageContextInfo.webAbsoluteUrl);
</pre>
For TypeScript to recognize the types in those statements, the declaration file SPScript.d.ts needs to define the various classes and parameters. I tried various combinations of statements in the declaration file, eventually using this:
<br />
<pre class="brush: jscript">export module SPScript {
export class RestDao {
constructor(webUrl: string);
}
}
</pre>
This approach allowed TypeScript to resolve the types, and the compiler successfully created a JS file.<br />
<br />
So, all ready to go? Nope - looking at the code in the compiled JS file, that statement had become
<br />
<pre class="brush: jscript"> var SPScript_1 = (typeof window !== "undefined" ? window['SPScript'] : typeof global !== "undefined" ? global['SPScript'] : null);
//... other statements
var dao1 = new SPScript_1.SPScript.RestDao(_spPageContextInfo.webAbsoluteUrl);
</pre>
That would fail in the browser, as the inclusion of the library SPScript.JS in the HTML page gives access to <em>SPScript.RestDao</em> not to <em>SPScript.SPScript.RestDao</em>.<br />
<br />
Plenty of investigation, trial and error lead to the use of this in the declaration file:
<br />
<pre class="brush: jscript">export class RestDao {
constructor(webUrl: string);
}
</pre>
The import statement was adjusted to
<br />
<pre class="brush: jscript">import { RestDao } from "./SPScript";
</pre>
And the successful outcome of the compile process gives this in the JavaScript file:
<br />
<pre class="brush: jscript"> var SPScript_1 = (typeof window !== "undefined" ? window['SPScript'] : typeof global !== "undefined" ? global['SPScript'] : null);
//... other statements
var dao = new SPScript_1.RestDao(_spPageContextInfo.webAbsoluteUrl);
</pre>
<h3 style="margin-bottom: 0px; margin-top: 1em;">
A note on the Global Name and Browserify-Shim</h3>
The ES5 JavaScript file is being created from the TypeScript modules with the help of Browserify within a Gulp task
<br />
<pre class="brush: jscript">gulp.task('package', ['includeLibs', 'compile'], () => {
let bundler = browserify({
entries: config.rootJS,
debug: true //This provides sourcemapping
})
.external(['./SPScript']);
bundler.bundle() //start buindling
.on('error', console.error.bind(console))
.pipe(exorcist(config.distOutputPath + '/' + config.bundleFile + '.map')) //Extract the sourcemap to a separate file
.pipe(source(config.bundleFile)) // Pass desired output file name to vinyl-source-stream
.pipe(gulp.dest(config.distOutputPath)); // Destination for the bundle
})
</pre>
Notice line 6 - this specifies that the SPScript is not to be included in any way in the output JavaScript. In addition, the global SPScript name needs to be made available within the bundled output modules. This is achieved by including the browserify-shim module in the source code, and adding the following to the package.json file:
<br />
<pre class="brush: jscript"> "browserify": {
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
"./SPScript": "global:SPScript"
}
</pre>
Note that the exact text used in the import statement - in this case it was <em>./SPScript</em> - must be passed to browserify-shim, so that the correct reference occurs within the compiled JavaScript.whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-28922906096189557242016-07-24T16:22:00.003-07:002016-07-24T16:26:26.241-07:00Modern JavaScript in SharePoint (4) - Gulp and PnP<div style="border: 1px solid rgb(224, 224, 224); margin: 10px; padding: 5px;">
The articles:<br />
<ul style="margin-top: 0px;">
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-motivation_72.html">Modern JavaScript in SharePoint (1) - the Motivation</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-2-visual-studio_37.html">Modern JavaScript in SharePoint (2) - Visual Studio Code</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-3-npm-and-gulp.html">Modern JavaScript in SharePoint (3) - npm and gulp</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-javascript-in-sharepoint-4-gulp.html">Modern JavaScript in SharePoint (4) - Gulp and PnP</a></li>
</ul>
</div>
PnP is the Office 365 Developer Patterns and Practices program - a (very) comprehensive resource illustrating techniques for coding against SharePoint and Office 365. Amongst the many offerings is the <a href="https://github.com/OfficeDev/PnP-JS-Core" title="Microsoft's JavaScript Core Library for SharePoint, on Github">JavaScript Core Library</a>. This library wraps the calls to the SharePoint REST API in a set of objects (or, to be accurate, in a series of namespaces and functions that mimic an object collection - this is ES5 JavaScript, after all!). The addition of this layer of abstraction simplifies many of the operations that are possible from client-side code.<br />
<br />
For example, submitting a search against SharePoint becomes as simple in JavaScript as this:
<br />
<pre class="brush: jscript">pnp.sp.search({ Querytext: "Document", RowLimit: 5 })
.then(function(data) { console.log(JSON.stringify(data)); })
.catch(function(e) { console.log("Error: " + e.message); });
</pre>
The calls in the library handle the asynchronous nature of the interactions
- hence the "then" and catch" functions for processing the retrieved data or any error that occurs.<br />
<br />
How can this library be incorporated into a build workflow using ES6/ES2015 JavaScript in Visual Studio Code? In my trials, I wanted to integrate the build and deployment process using gulp, so first I investigated options for upload files to SharePoint Online within a gulp task. And happily there is a gulp plugin ready to achieve that - its called <a href="https://www.npmjs.com/package/gulp-spsave" title="gulp-spsave plugin in the npm site">gulp-spsave</a>. It is very simple to use, with the only disadvantage being that the credentials used to connect to Office 365 are supplied as plain text within the call. An alternative is to use <a href="https://github.com/wictorwilen/gulp-spsync" title="gulp-spsync on Github">gulp-spsync</a> by Wictor Wilen - but for the purposes of these tests I have stuck with the spsave plugin.<br />
<br />
This allows the upload of files into the site assets library in SharePoint to be achieved by:
<br />
<pre class="brush: jscript">gulp.task('upload-sp', function () {
return gulp.src(config.bundleFilePath)
.pipe(print())
.pipe(spsave({
username: settings.username,
password: settings.password,
siteUrl: settings.siteUrl,
folder: "SiteAssets",
notification: true
}));
})
</pre>
In this task, the account details and the target site are stored in a separate settings JSON file. I also have a separate similar task to upload libraries, such as PnP and any other dependencies.<br />
<h3 style="margin-bottom: 0px; margin-top: 1em;">
Compiling PnP in Typescript in Visual Studio Code</h3>
So, now to use PnP in JavaScript in Visual Studio Code. First step is to add the module into the code's folder structure using the npm call on the command line (in the useful integrated terminal window):<br />
<div align="center">
npm install --save-dev sp-pnp-js</div>
This adds a folder into the node_modules directory tree that includes the pnp.js library. <br />
<br />
Next, the PnP library needs to be imported into the JavaScript module in which calls will be made using the library. In ES6/ES2015 this is achieved by the line
<br />
<pre class="brush: jscript">import * as pnp from "sp-pnp-js";
</pre>
That seemed simple. But its not quite that easy. When I added a PnP call in my code in Typescript, and attempted to compile it using the Typescript compiler, I received various errors. Visual Studio Code started giving several naming errors. The TypeScript compiler was looking into PnP.js and finding lots of names it did not recognize. <br />
<br />
At run time in the browser, these names would be available in the global namespace as the PnP library is built knowing that various other JS libraries are always referenced from SharePoint pages. But the point of using strongly typed JavaScript is to check its validity at compile time, so the compiler needs to know about all names used in all the current scripts. So I needed to supply the compiler with references for all names used in PnP.js.
Experimentation lead to the following inclusions for overcoming the compile errors:
<br />
<ul>
<li>PnP is dependent on ES6 Promise and on whatwg fetch at runtime, so the type definitions for these libraries are needed. As an example, a compile error may complain of "promise" being an unknown name. These definitions can be added to the source code in VS Code via the following statements which get the necessary files from the DefinitelyTyped online resource:
<div align="center">
typings install dt~es6-promise --global --save
<br />
typings install dt~whatwg-fetch --global --save</div>
</li>
<li>PnP also makes considerable use of the Microsoft Ajax library. I could not find a command line statement with which to add this type, so ended up manually getting the <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/microsoft-ajax/microsoft.ajax.d.ts">Microsoft-ajax.d.ts file</a> from a GitHub location. I then manually added a sub-folder under the typings globals folder structure, and included a reference to this in the index.d.ts file under typings.</li>
<li>Last name correction was to add SharePoint-specific name declarations. For these, I found a file <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/sharepoint/SharePoint.d.ts">SharePoint.d.ts</a> which I also manually added to the typings in this source. </li>
</ul>
This took a while, but finally managed to get the Typescript compiler to accept PnP!
<br />
<h3 style="margin-bottom: 0px; margin-top: 1em;">
Bundling The JavaScript for Deployment</h3>
Once the code could be compiled into an ES5 file, the ES5 then was ready for use on a test SharePoint page. Or was it? Looking at the file created using browserify in a gulp task, it was a huge file, as it included all of the PnP library. Clearly this is not what we want (as the PnP.js minimized library would be referenced from the page), so needed to tell browserify to exclude that library. This is done using the "external()" command:
<br />
<pre class="brush: jscript"> return browserify({
entries: config.sourceJS + 'spTests.js',
debug: true //This provides sourcemapping
})
.external(['sp-pnp-js'])
.bundle()
.on('error', console.error.bind(console))
.pipe(source(config.bundleFile)) // Define the name of the bundle
.pipe(gulp.dest(config.tsOutputPath)); // Destination for the bundle
</pre>
In this gulp task, the compiled file "sptests.js" is being prepared for upload - the reason I am taking this approach is to be able bundle multiple modules into a single file. The second command in the pipeline tells browserify not to include the pnp.js library in the bundled output. Great, the completed file is now much smaller.
<br />
<h3 style="margin-bottom: 0px; margin-top: 1em;">
Using the file in SharePoint</h3>
The bundled file is uploaded to SharePoint using gulp-spsave, along with the libraries on which it is dependent. It nearly ran in the test page, but showed an error - the name "pnp" was not recognized in the script available on the page. Looking at the PnP library, it exposes "$pnp" rather than "pnp". So the gulp process needed to somehow map all calls to pnp to actually use $pnp.
<br />
browserify-sim to the rescue. Adding the following to the package.json file, and running the gulp tasks again, gave a bundled ES5 file that successfully uses PnP calls!
<br />
<pre class="brush: jscript"> "browserify": {
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
"sp-pnp-js": "global:$pnp"
}
</pre>
<h3 style="margin-bottom: 0px; margin-top: 1em;">
Thoughts on the Process</h3>
As you can see, writing code in Visual Studio Code in Typescript against PnP and getting that code to run in a SharePoint page is at the moment a mission. I am sure it will get easier.... If you need any tips about the concepts here, please drop leave a comment & I'll be in touch.
whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-28973650057504887972016-07-21T15:28:00.000-07:002016-07-21T15:30:07.059-07:00Reflections on Learning React....What's quiet amusing (and frustrating….) is that the simplest user interactions with page elements have to be relearnt in a way fitting the paradigms of the React model. As an example, imagine a search form. Just a text box and a button, simple right? In "classic" JS, adding an onclick event handler to read and search on the value in the textbox takes no thought at all (ignoring here the "production -quality" trimmings that are necessary in a real world form, such as validation).<br />
<br />
Reproducing this interaction in React requires knowledge of a few principles:
<br />
<ul>
<li>Event handlers are attached to an element as a property. If using JSX, be careful not to enclose the handler in quotes!
<pre class="html-script:true"> < input onclick={this.submitSearch} type="button" value="Search" />
</pre>
</li>
<li>The "this" context pointing to the React component is not available in the event handler. That means that if the value in the text box is bound to a member of the component state, this value would not be accessible in the handler. There are two approaches to correcting this - either add the "bind(this)" call to the end of the handler invocation
<pre class="html-script:true"> < input onclick={this.submitSearch.bind(this)} type="button" value="Search" /> </pre>
or define the handler as an arrow function
<pre class="brush:jscript">submitSearch = ( e ) => { … }</pre>
</li>
<li>Bind the text box default value to an initial value. Do not bind the value property, as doing so causes the box to behave as read only in the form. Also need to add an onchange handler for the text box, bound to a function that updates the appropriate member of the state object with the value from the control (e.target.value)</li>
<li>Add the shouldComponentUpdate() lifecycle function to the component, ensuring that the change of text value in the state member does not trigger the update (unless you want the search to occur on every key stroke)</li>
<li>Setting the state in React (using Typescript in VS Code) requires all members of the state object to be set each time
</li>
</ul>
whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-47651716134348762232016-07-19T21:18:00.001-07:002016-07-19T21:18:22.049-07:00Browserify is Sensitive in its Entry Files Parameter - "Cannot Find Module" ErrorFaced an issue today whilst using <a href="https://github.com/substack/node-browserify">Browserify</a> to bundle some JavaScript files. The JS files had been compiled in Visual Studio Code from Typescript TSX files via gulp, and were all stored together in a single intermediate folder. <br />
<br />
The single JS output bundle file was created just fine by Browserify. But when used in an HTML page, that file would result in a "cannot fund module" error. This error is created in the _prelude.js module, part of the output from Browserify. <br />
<br />
So, it was time to explore the contents of the bundled JavaScript file. That file contains sections for each of the bundled modules. The last of those modules is generally the one that executes after loading. If that module needs to reference methods or properties exported by other modules, then there should be a mapping between the exported module name and that module key in the bundled modules array. Looking at the end of my output file, that mapping was as follows:<br />
<br />
<div style="text-align: center;">
},{<span style="font-weight: bold;">"./AppHeader":undefined</span>}]},{},[1,2,3,4])</div>
<br />
This means that the "AppHeader" module was not reachable, leading to that "cannot find module" error. After plenty of research into the bundling tool (during which I came across <a href="http://benclinkinbeard.com/posts/how-browserify-works/">this useful article</a> by Ben Clinkinbeard that describes the Browserify actions), I went back to look at the calling task in gulp. There I found that the Entry Files parameter was using a glob to point at all the JS files in the intermediate folder - the result of some previous testing in a project on which this set of files was based.<br />
<br />
I changed this parameter to point just at the single root JS file, reran the bundling task in gulp, and now the output file ended with this:<br />
<div style="text-align: center;">
},{<span style="font-weight: bold;">"./AppHeader":1</span>}]},{},[2])</div>
<br />
This new bundled file worked just fine in the browser. So beware the Entry Files parameter!<br />
<br />
PS For lots more details on this tool, consult <a href="https://github.com/substack/browserify-handbook">the Browserify handbook</a>!whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com1tag:blogger.com,1999:blog-5760703966775804012.post-2729506227436428452016-07-19T14:42:00.001-07:002016-07-19T14:50:59.661-07:00Modern JS in SharePoint (3) - NPM and Gulp<div style="border: 1px solid rgb(224, 224, 224); margin: 10px; padding: 5px;">
The articles:<br />
<ul style="margin-top: 0px;">
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-motivation_72.html">Modern JS in SharePoint (1) - the Motivation</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-2-visual-studio_37.html">Modern JS in SharePoint (2) - Visual Studio Code</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-3-npm-and-gulp.html">Modern JS in SharePoint (3) - npm and gulp</a></li>
</ul>
</div>
Here's a quick analogy to help visualize the difference between using Visual Studio and Visual Studio Code. Imagine you need to build a bookshelf. You can pop into Ikea, select a few shelf unit to suit your needs, add a few accessories, and then spend an hour or two at home assembling the units. All the instructions and the fittings are in the kit. <br />
<br />
Alternatively you can build from scratch, selecting the wood, learning to use the right tools for each task, choosing the hardware from the huge available range of screws & bolts & brackets. Along the way you gain skills with the tools, and create something totally customized for your needs.<br />
<br />
No doubt you see where this is leading.... Starting our with VS Code feels a little like an apprenticeship, with so many new techniques and concepts to master. The familiar development workflow in Visual Studio of "New Project..." is replaced when using VS Code by decisions of what tools and facilities I need in this project, and what build steps will be appropriate.<br />
<br />
I think this is a good learning process to face. Disrupting our normal routines can be painful at first, but helps make us aware of new and better ways to do things. Core to the new development workflow is npm, the Node Package Manager. This is usually compared to Nuget, but npm is a more vital element in the process than Nuget is in VS.<br />
<br />
There is plenty of guidance on the web of how to install <a href="https://nodejs.org/en/download/">Node</a> and <a href="https://docs.npmjs.com/getting-started/installing-node">npm</a>, so I won't repeat it here (in case you were wondering, Node runs JavaScript code in a background process, and is required if using npm & gulp). I will, however, mention the usefulness of the integrated terminal window in VS Code (<em>CTRL+`</em>) - that has been the place in which I have carried out all the command-line work necessary in my projects.
<h3 style="margin-top:1em;margin-bottom:0;">Starting a New Development Project</h3>
Visual Studio Code focusses on files within a folder structure. The tools used within the editor expect files with particular names to be in certain locations in that folder structure - convention over configuration. The general principle when starting from scratch is to create a top level folder for you new development files, open that folder in VS Code, and then run the following:<br />
<div style="text-align: center;">
npm init -y</div>
This creates the package.json file, similar in some ways to the project file in VS - it stores high-level settings for your development project, including the node modules that are used during the development operations.
<h3 style="margin-top:1em;margin-bottom:0;">Tailoring the Development Workflow</h3>
Node modules are plugins that can add content to your development project (such as libraries needed in your code). And node modules can also add task handlers to help with the development workflow. We are working here in the open source world, so there are a variety of "competing" options when choosing how to automate and orchestrate tasks in your development process. By this, I mean the ability for the development environment to do such things as check the quality of our source code("linting"), running tests, translate coding languages into runnable formats (compiling or "transpiling"), and packaging the source code for deployment.<br />
<br />
The main players at the time of writing for creating workflows from these tasks (otherwise known as task runners) are <a href="http://gulpjs.com/">gulp</a> and <a href="http://gruntjs.com/">grunt</a>. An alternative is to use <a href="https://webpack.github.io/">webpack</a> which is a bundling tool that is able to run tasks other than just bundling files. Each takes a different approach to automating tasks. Each can suit different projects, or can seem a better fit for our own way of working. Gulp defines the operations to perform in JavaScript, whereas grunt (and webpack) use configuration files to define the operations.
<h3 style="margin-top:1em;margin-bottom:0;">Using gulp</h3>
After some experimentation with webpack and gulp, personally I prefer gulp. It gives me huge flexibility in how I organise the development tasks, is easier to debug through the use of logging statements to explore status of the tasks, and I find it easier to visualize thanks to the low-level step-by-step control. But you may prefer one of the other approaches - as I say, its down to personal preference, as you can probably achieve the same outcomes with any of the approaches. <a href="http://jamesknelson.com/which-build-system-should-i-use-for-my-javascript-app/">James Nelson</a> provides some useful ideas on this subject. <br />
<br />
If you choose to use gulp, it is worthy to know that the gulpfile can be written in ES6/ES2015 - <a href="https://markgoodyear.com/2015/06/using-es6-with-gulp/">this article by Mark Goodyear</a> explains how to achieve this (using babel, and renaming the gulpfile). Why do this? Its another opportunity to become familiar with the new coding styles in ES6/ES2015<br />
<br />
In the next installment, I will explain the gulp configuration I have found useful.whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-28784332612710562222016-07-18T14:18:00.003-07:002016-07-19T14:43:42.407-07:00Modern JS in SharePoint (2) - Visual Studio Code<div style="margin: 10px; padding: 5px; border: 1px solid rgb(224, 224, 224); border-image: none;">
The articles:<br>
<ul style="margin-top: 0px;">
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-motivation_72.html">Modern JS in SharePoint (1) - the Motivation</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-2-visual-studio_37.html">Modern JS in SharePoint (2) - Visual Studio Code</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-3-npm-and-gulp.html">Modern JS in SharePoint (3) - npm and gulp</a></li>
</ul>
</div>
How to compare the Visual Studio full IDE with Visual Studio Code? If the VS IDE were a high spec campervan, replete with every mod con and comfort to offer good living anywhere, VS Code is the nippy little two door sports car. Pared-down for speed and performance, but with enough optional extras to allow for comfort as well as fun (so, more Porsche than Mazda!).<br />
<br />
SharePoint development used to need access to the server-side objects, allowing the compiled code to interact directly with the farm. In the newer world of building at the front end, that tight coupling is replaced by remote hosted compiled apps or by client-side code. So Visual Studio no longer needs to run on a SharePoint server. <br />
<br />
The lightness of Visual Studio Code is refreshing. It loads quickly on my laptop, and it views my work as files in a series of folders rather than as solutions or projects. Extensions are available in a <a href="https://marketplace.visualstudio.com/VSCode">Marketplace</a>, but for now I am keeping my install lean - after spending time recently investigating a problem in Visual Studio Professional related to a troublesome extension, I am keen to reduce the potential for add-ins to cause me difficulties. The marketplace includes extensions to aid the development workflow, such as tools to check the quality of your code (linters and validators) - but I suggest ignoring these for now. Instead, have a go with the task runners and associated tools from the world of Node. One of the huge benefits is that you'll gain web dev experience applicable beyond the SharePoint "walled garden".<br />
<br />
I challenge you to look through the list of extensions you have installed in Visual Studio, and think about which of those you actually use? I know the feeling... "that looks useful, I'll install it and might use it later..."!<br />
<br />
Learn the <a href="https://code.visualstudio.com/docs/customization/keybindings">VS Code shortcut keys</a>, and you can quickly be cruising along concentrating on writing good code rather than on nurturing the development environment. The integrated terminal window will soon become very useful in this new world of npm and task runners, so <em>CTRL+`</em> is a good combination to learn straight away.<br />
<br />
You can grab VS Code from <a href="https://code.visualstudio.com/Download">here</a> - last time I downloaded the setup package, it was about 60MB in size.whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-51238898919182627282016-07-17T14:51:00.004-07:002016-07-19T14:43:05.963-07:00Modern JS in SharePoint - the Motivation<div style="margin: 10px; padding: 5px; border: 1px solid rgb(224, 224, 224); border-image: none;">
The articles:<br>
<ul style="margin-top: 0px;">
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-motivation_72.html">Modern JS in SharePoint (1) - the Motivation</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-2-visual-studio_37.html">Modern JS in SharePoint (2) - Visual Studio Code</a></li>
<li><a href="https://sharethelearning.blogspot.co.nz/2016/07/modern-js-in-sharepoint-3-npm-and-gulp.html">Modern JS in SharePoint (3) - npm and gulp</a></li>
</ul>
</div>
When building customisations and enhancements for SharePoint, JavaScript has been my technology of choice for the last few years. It simplifies the life cycle management, works across SharePoint Online or on-premises, and offers a huge foundation of libraries upon which to build. It also is being acknowledged as the way forwards within the SharePoint product itself - the "Modern Document Library" released in Office 365 uses the React JS framework.<br />
<br />
I have to admit, though, that my JavaScript was being created in the "old fashioned" way. No ES6, no build process, just the "quick" approach of a simple file in the style library within SharePoint. That approach brings the benefits of simplicity in structure, of being quickly updateable where needed, and of requiring just a text editor plus the dev tools in the browser. It is a very effective technique for small enhancements such as modifying the display of a column in a list view. <br />
<br />
But those benefits are eclipsed by the downsides when building bigger applications in JavaScript. Very quickly a single JS file becomes too long. Encapsulating methods and properties in <a href="http://benalman.com/news/2010/11/immediately-invoked-function-expression/">IIFEs</a> helps to some extent, but refactoring and testing becomes hard. The code becomes sensitive to change. A better way is needed.<br />
<br />
One such "better way" is to adopt the tools and practices that are commonplace in the open-source web dev world. Amongst these are the use of:<br />
<ul>
<li>Coding in modern JavaScript - ES6 and/or Typescript</li>
<li>"Transpiling" that code into JavaScript that is compatible with current browsers (as the browsers are not keeping up with all features in the standards) - Babel</li>
<li>Packaging the code to improve download times and browser processing</li>
<li>Configuring flexible build processes through the creation of task runners - Gulp</li>
<li>Manipulating code in nimble code editors rather than heavy-weight development environments - Visual Studio Code</li>
</ul>
It's a lot of change! I dived into that world last week, and getting to the first speck of working code in a SharePoint page has been a challenge, for sure. Here I would like to document some of the things I have tried, and the lessons I have learnt. The combination of tools in my new working set are not necessarily the right fit for your circumstances. I am not suggesting that this combination of tools and techniques are recommended as being best of breed - they are the ones that are working for me at present. My aim in this small set of articles is to give a little help if you are interested in the evolution to "enterprise-scale" front-end development for SharePoint. whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-78967642352635850452014-05-27T16:40:00.000-07:002014-05-27T16:40:14.507-07:00A hidden benefit of presenting...A big benefit of presenting technical subjects is the surprising new tangents that open to widen your existing knowledge of a subject. When preparing demos for SharePoint or JavaScript sessions, I often find that an investigation into data or techniques to enliven an example will uncover lots of new ideas and approaches that can benefit my every day work.<br />
<br />
As an example, recently I was preparing a session on Visualising data in SharePoint through the use of OData and client-side code, and came across the wonders of <a href="https://github.com/square/crossfilter/wiki/API-Reference">Crossfilter</a> for analysing/processing large data sets on the client. That (and the similar library "<a href="http://nytimes.github.io/pourover/">PourOver</a>") look to make this type of data presentation very efficient. Looking forward to doing more with them.<br />
<br />
Have you used these libraries yourself? Any good or bad experiences to share?whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-49674927419372788052014-03-26T15:58:00.002-07:002014-03-26T15:58:20.000-07:00More "Small Steps in SharePoint" guidesToday I have published two more Small Steps in SharePoint (and Office 365) guides to achieving everyday tasks in the system:<br />
<ul>
<li><a href="http://www.smallsteps.co.nz/ShareAFile.aspx">How to share a document with someone inside your company</a></li>
<li><a href="http://www.smallsteps.co.nz/ShareAFileExternally.aspx">How to share a document externally</a> - to someone outside your organisation</li>
</ul>
If you have any suggestions or requests on other tasks I could cover in these guides, please let me know and I will add new ones to the set.whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-41750747532796437402013-10-15T13:46:00.000-07:002013-10-15T13:46:28.015-07:00Reducing all that White Space in a SharePoint 2013 Page<span style="font-family: inherit;">Web
part pages in SharePoint 2013 render with large spaces between the web part zones. It turns
out to be caused by a border-spacing style applied to the ms-webpartPage-root
class. Adjusting this to 0px removes lots of the unnecessary white space. Now white space is a Good Thing in design (but in the case of these web part pages it seems to be a little too much of a good thing!). One way is to include the following CSS:</span><br />
<div align="center">
<em>.ms-webpartPage-root { border-spacing:0px !important; }</em></div>
whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com2tag:blogger.com,1999:blog-5760703966775804012.post-45680808572796267822013-08-12T20:56:00.000-07:002013-08-12T20:56:09.589-07:00Solving Office 365 SkyDrive Pro Sync Problem (error 0x80040208)SkyDrive Pro eases the process of uploading lots of files into a SharePoint document library - but can stop working if a file added to the SkyDrive Pro folder has a name that is longer than 64 characters.<br />
<br />
When a file with a long file name is dragged into the SkyDrive Pro folder, you may find that anyone with a folder mapped to the associated SharePoint document library start seeing messages about syncing problems. The SkyDrive Pro folder icon will also show an error in Windows Explorer.<br />
<br />
One way to see if long filenames could be causing these problems is to search for all files in a library with long file names. To find all such files for a client, I created the following JavaScript that uses a CSOM (Client Side Object Model) query to get all files in a library (even if the files are located in folders in the library) and to display a list of all the problematic file names.<br />
<br />
To use this code, add a new page to your site, edit the page and add "embedded script" into that page. Edit the source of that script, and paste the following HTML into the page - be sure to adjust the value in hostweburl to match the URL of your Office 365 site, and the value in documentLibraryTitle to match the display title of the document library you wish to test.<br />
<br />
For more notes on the code, see my article at <a href="http://www.smallsteps.com/skydriveprosyncproblem.aspx">on this subject on my site</a><br />
<br />
This code could be extended with a little work to offer all the document libraries in a site in a dropdown - if you have any ideas for extensions, or want help with the code, please leave a comment<br />
<pre><div style="background: #ffffff; border-width: .1em .1em .1em .8em; border: solid gray; overflow: auto; padding: .2em .6em; width: auto;">
<pre style="line-height: 125%; margin: 0px;"><span style="color: #007700;"><script </span><span style="color: #0000cc;">src=</span><span style="background-color: #fff0f0;">"//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"</span> <span style="color: #0000cc;">type=</span><span style="background-color: #fff0f0;">"text/javascript"</span><span style="color: #007700;">></script></span>
<span style="color: #007700;"><script </span><span style="color: #0000cc;">type=</span><span style="background-color: #fff0f0;">"text/javascript"</span><span style="color: #007700;">></span>
<span style="color: #008800; font-weight: bold;">var</span> hostweburl; <span style="color: #888888;">//Web URL</span>
<span style="color: #008800; font-weight: bold;">var</span> ctx; <span style="color: #888888;">// Client context</span>
<span style="color: #008800; font-weight: bold;">var</span> documentLibraryTitle <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'Documents'</span>; <span style="color: #888888;">//The title of the document library in which to seek long filenames</span>
$(<span style="color: #007020;">document</span>).ready(<span style="color: #008800; font-weight: bold;">function</span> () {
<span style="color: #888888;">//Full URL to the Office 365 site collection root web</span>
hostweburl <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'https://yoursite.sharepoint.com'</span>;
<span style="color: #888888;">// The js files are in a URL in the form: web_url/_layouts/15/resource_file</span>
<span style="color: #008800; font-weight: bold;">var</span> scriptbase <span style="color: #333333;">=</span> hostweburl <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">"/_layouts/15/"</span>;
<span style="color: #888888;">// Load the js files and continue to the execOperation function.</span>
$.getScript(scriptbase <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">"SP.Runtime.js"</span>,
<span style="color: #008800; font-weight: bold;">function</span> () {
$.getScript(scriptbase <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">"SP.js"</span>, execOperation);
}
);
});
<span style="color: #888888;">//Main process, runs once the SP.Runtime.js and SP.js files have dynamically loaded</span>
<span style="color: #008800; font-weight: bold;">function</span> execOperation() {
ctx <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> SP.ClientContext();
retrieveItems();
}
<span style="color: #008800; font-weight: bold;">function</span> retrieveItems() {
<span style="color: #008800; font-weight: bold;">var</span> clientContext <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> SP.ClientContext();
<span style="color: #008800; font-weight: bold;">this</span>.oList <span style="color: #333333;">=</span> clientContext.get_web().get_lists().getByTitle(documentLibraryTitle);
<span style="color: #888888;">//Could use the following to create the query text "<View Scope='RecursiveAll'><Query></Query></View></span>
<span style="color: #888888;">//var camlQuery = SP.CamlQuery.createAllItemsQuery();</span>
<span style="color: #888888;">//BUT this does not sort, and we need to sort by folder here</span>
<span style="color: #008800; font-weight: bold;">var</span> camlQuery <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">new</span> SP.CamlQuery();
<span style="color: #888888;">//Get all documents from all folders</span>
<span style="color: #008800; font-weight: bold;">var</span> query <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'<View Scope="RecursiveAll"><Query><OrderBy><FieldRef Name="FileDirRef" /></OrderBy></Query></View>'</span>;
camlQuery.set_viewXml(query);
<span style="color: #008800; font-weight: bold;">this</span>.collListItem <span style="color: #333333;">=</span> oList.getItems(camlQuery);
<span style="color: #888888;">//Only get the title and path information in order to reduse size of returned data</span>
clientContext.load(collListItem, <span style="background-color: #fff0f0;">'Include(Title,FileDirRef,FileLeafRef)'</span>);
clientContext.executeQueryAsync(
<span style="color: #007020;">Function</span>.createDelegate(<span style="color: #008800; font-weight: bold;">this</span>, <span style="color: #008800; font-weight: bold;">this</span>.onListItemsQuerySucceeded),
<span style="color: #007020;">Function</span>.createDelegate(<span style="color: #008800; font-weight: bold;">this</span>, <span style="color: #008800; font-weight: bold;">this</span>.onListItemsQueryFailed)
);
}
<span style="color: #008800; font-weight: bold;">function</span> onListItemsQuerySucceeded() {
<span style="color: #008800; font-weight: bold;">var</span> titles <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">''</span>;
<span style="color: #008800; font-weight: bold;">var</span> listEnumerator <span style="color: #333333;">=</span> <span style="color: #008800; font-weight: bold;">this</span>.collListItem.getEnumerator();
<span style="color: #008800; font-weight: bold;">var</span> loopCount <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">var</span> prevFolder <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'zzz'</span>;
<span style="color: #008800; font-weight: bold;">while</span> (listEnumerator.moveNext()) {
<span style="color: #008800; font-weight: bold;">var</span> oItem <span style="color: #333333;">=</span> listEnumerator.get_current();
<span style="color: #008800; font-weight: bold;">var</span> fileName <span style="color: #333333;">=</span> oItem.get_item(<span style="background-color: #fff0f0;">'FileLeafRef'</span>);
<span style="color: #008800; font-weight: bold;">var</span> folderUrl <span style="color: #333333;">=</span> oItem.get_item(<span style="background-color: #fff0f0;">'FileDirRef'</span>);
<span style="color: #888888;">//If the filename is longer than 63 characters, display a message</span>
<span style="color: #008800; font-weight: bold;">if</span> (fileName.length <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">63</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (prevFolder <span style="color: #333333;">!=</span> folderUrl)
{ titles <span style="color: #333333;">+=</span> <span style="background-color: #fff0f0;">'<div style="font-weight:bold;"><a href="'</span> <span style="color: #333333;">+</span> hostweburl <span style="color: #333333;">+</span> folderUrl <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">'" target="_blank">'</span> <span style="color: #333333;">+</span> folderUrl <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">'</a></div>'</span>; }
titles <span style="color: #333333;">+=</span> <span style="background-color: #fff0f0;">'<div style="padding-left:10px;">'</span> <span style="color: #333333;">+</span> fileName <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">'(length: '</span> <span style="color: #333333;">+</span> fileName.length <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">')</div>'</span>;
prevFolder <span style="color: #333333;">=</span> folderUrl;
}
loopCount<span style="color: #333333;">++</span>;
}
AddMessage(titles);
}
<span style="color: #008800; font-weight: bold;">function</span> onListItemsQueryFailed(sender, args) {
alert(<span style="background-color: #fff0f0;">'Request failed. '</span> <span style="color: #333333;">+</span> args.get_message() <span style="color: #333333;">+</span> <span style="background-color: #fff0f0;">'\n'</span> <span style="color: #333333;">+</span> args.get_stackTrace());
}
<span style="color: #007700;"></script></span>
<span style="color: #007700;"><div</span> <span style="color: #0000cc;">id=</span><span style="background-color: #fff0f0;">"results"</span><span style="color: #007700;">></div></span>
</pre>
</div>
</pre>
whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-24185464831724324112013-08-04T21:16:00.000-07:002013-08-04T21:16:58.092-07:00PowerShell to Find ListItems Modified Since a DateAssuming that the list to be queried is already referenced in the $list object in script, here is a simple snippet to retrieve all list items that have been modified within the last one hundred days:<br />
<br />
$previousRunDate = [Microsoft.SharePoint.Utilities.SPUtility]::CreateISO8601DateTimeFromSystemDateTime([DateTime]::Now.AddDays(-100))
$camlModifiedDateQuery = '<where><Gt><FieldRef Name="Modified" /><Value Type="DateTime">{0}</Value></Gt></Where>' -f $previousRunDate
$query = New-Object Microsoft.SharePoint.SPQuery
$query.Query = $camlQuery
$listItems = $list.GetItems($query)
$previousRunDate = [Microsoft.SharePoint.Utilities.SPUtility]::CreateISO8601DateTimeFromSystemDateTime([DateTime]::Now.AddDays(-100))
$camlModifiedDateQuery = '<where><gt><fieldref name="Modified"><value type="DateTime">{0}</value></fieldref></gt></where>' -f $previousRunDate
$query = New-Object Microsoft.SharePoint.SPQuery
$query.Query = $camlQuery
$listItems = $list.GetItems($query)whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-87833403655605426442013-08-04T21:15:00.001-07:002013-08-04T21:18:02.540-07:00User Profiles missing from SharePoint 2010 People Search ResultsPleasantly surprising how a small configuration change can correct seemingly unrelated errors - people search in a SharePoint 2010 site which I assist with was missing hundreds of people from the search results listing.
<br />
<br />
The search log was showing a large number of errors stating "Error in PortalCrawl Web Service" each associated with a URL for the person.aspx page with an accountname in the querystring. Clicking on any of these URLs from the crawl log gave a "User not found" error. An interesting thing in these was that the account names had the wrong delimiting character - they were showing domain/username rather than domain\username.
<br />
<br />
Also there was one top level error stating showing that the crawl of the sps3 source failed. This was due to the default content access account not having the necessary administrator permissions on the User Profile service application. Granting the "Retrieve People Data for Search Crawlers" permission for that account solved the Top Level error, and also had the effect of removing all the crawl log entries for the person.aspx crawl.
<br />
<br />
So the users are now showing in the search results, and everyone is happy!whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-40256640908627502742012-09-11T20:03:00.001-07:002012-09-11T20:03:17.048-07:00SharePoint 2013 Preview Popup Menus MissingAfter re-installing SharePoint 2013 Preview to fix an issue on a test server, I found that the popup menus (such as the settings menu at the top right corner) did not work in IE9. Those areas did not change background colour, either, when hovering over the location.
Yet they worked in FireFox!
Eventually I removed the server name from the local intranet zone in IE - and the menus started working again. Tried replicating the issue by adding the URL back to that zone, but can't get it to happen again. Beware!whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com1tag:blogger.com,1999:blog-5760703966775804012.post-12368156249256117072012-01-17T13:54:00.000-08:002012-01-17T13:54:45.492-08:00HTML5 Learnings - Getting IE9 to Accept Canvas ElementsWorking with HTML5 at the moment is a lot like the "good old days" of designing pages to work in IE, then redoing the page for Navigator (oooh, showing my age in the industry there!)<br />
<br />
Anyhows, today's little lesson was about a small subtly in IE9 behaviour when handling a page incorporating Canvas elements. Initial I was working on the page in Web Expression, and viewing the page via a "file://..." path in the IE9 address bar. All was fine, and the JavaScript rendering the canvas element content worked OK.<br />
<br />
But then I copied the HTML into a page being served up through IIS, and accessed via an "http://..." address. Looking at this new page, IE9 now tells me that the canvas element is not supported (modernizr adding the "<strong>no-canvas</strong>" class to the html element). Weird. Much playing later, found that it is necessary to add the following header metatag to the page:<br />
<br />
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<br />
<br />
Seems that IE treats pages accessed from the file-system differently that those from an http address!whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-72766485711040300782012-01-04T20:57:00.000-08:002012-01-04T20:57:09.200-08:00Setting BCS Secondary Fields Programmatically in SharePoint 2010Phew, that was quite a battle. I have been writing some code to import values from a CSV file into some custom lists in SharePoint (I realise that there are, of course, plenty of other ways to import into SharePoint, such as using PowerShell or a third party app., but specific needs call for special handling), and one of the requirements is to import data into External Columns in the SharePoint list.<br />
<br />
Original this process used the GetSecondaryFieldNames() method of the SPBusinessDataField instance to get the internal names of each of the secondary fields, and then combined each of those with the internal name of the SPBusinessDataField to create the displayname value for each secondary field. The list item fields could then be set using these displayname values.<br />
<br />
This worked fine in the dev environment... but of course the real workd is different! Researching the failure of this process on the target machine showed that the display names for the secondary fields did not contain the values from the GetSecondaryFieldNames() call (PowerShell allowed me to easily view the Schema XML for the fields in the list, saving the need for a tool like SharePoint Manager).<br />
<br />
So, my solution was to seek the secondary field by enumerating through all fields in the list, seeking the field whose: <br />
<ul>
<li>"DisplayName" property value starts with the internal name of the related external data field </li>
<li>"BdcField" property value matches a string value returned by GetSecondaryFieldNames()</li>
</ul>
<span style="font-family: Consolas;"><span style="font-family: Times New Roman;">This lets me find the required secondary BCS field, and gived me the GUID for use in later populating that field with a value. </span></span><span style="font-family: Consolas;"><span style="font-family: Times New Roman;">I then make sure to cache this GUID, meaning on the next pass through this part of the code I can use the cached value rather than re-enumerating all the fields once again.</span></span><br />
<span style="font-family: Consolas;"></span>whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-63909540963392836822011-10-25T15:44:00.000-07:002011-10-25T15:44:40.988-07:00FileNotFoundException with "new SPSite" CallThis one came back to bite me again, so time to note it down here - when running any test code which accesses a SharePoint web or site using new SPSite(url) in a console application, or in a Visual Studio 2010 test project, it is necessary to adjust the build properties of the project. <br />
<br />
The project build configuration (the second tab down in the project properties) need to have the Platform Target explicitly set to x64. If this target is set to x86, or possibly to "Any CPU" then the call to "new SPSite" will fail with "FileNotFoundException", stating that "The web application cannot be found". Next time I'll remember...whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-27372836807926934042011-10-19T01:19:00.001-07:002011-10-19T01:21:14.829-07:00Error in Visual Studio 2010 Packaging a SharePoint 2010 SolutionWas getting an error stating that a file "deploys to the same package location" when packaging a SharePoint 2010 solution in VIsual Studio 2010. <br />
<br />
Turns out that the SharePointProjectItem.spdata file (in the module subfolder within the Visual Studio project) had somehow gained duplicate entries for a particular file.
<br />
To fix this,
<br />
<ol>
<li>Unload the project in VS (or close the entire solution)</li>
<li>Find the SharePointProjectItem.spdata file in Windows Explorer, and edit in Notepad++ (or your favourite text editor!) to remove the duplicate reference</li>
<li>Reload the project in VS, and select that "Package" action - all then worked for me.</li>
</ol>whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-87297775992595308922011-09-29T01:56:00.000-07:002011-09-29T01:56:54.561-07:00Cannot Log in with Microsoft LyncTook a while to track this one down - a fresh install of Lync refused to connect or login to Office 365. Experimented with adjusting the manual configuration settings as suggested by lots of posts, but to no avail. Finally found a comment on a forum suggesting to check the time on the computer. The time was in fact a few minutes fast - so I set the time, restarted Lync, and login worked straight away. Who'd have thought?!whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-28535640396609651112011-09-13T15:53:00.000-07:002011-09-13T15:53:07.892-07:00Cant Seem to Remove Columns from a Content Type in a SolutionSome behaviours in SharePoint 2010 solutions have become frustrating compared with SharePoint 2007 solutions. One that's particularly troublesome is attempting to modify site columns in a custom content type that inherits from a non-built in content type.<br />
<br />
When inheriting from a publishing article page content type using a solution, just can't seem to remove a couple of site column. Neither of the following approaches seems to work. If I come up with a solution, I'll add it hear.<br />
<br />
<span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> <</span></span><span style="color: #a31515; font-family: Consolas;"><span style="color: #a31515; font-family: Consolas;">FieldRef</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> </span></span><span style="color: red; font-family: Consolas;"><span style="color: red; font-family: Consolas;">ID</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">=</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">{d3429cc9-adc4-439b-84a8-5679070f84cb}</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> </span></span><span style="color: red; font-family: Consolas;"><span style="color: red; font-family: Consolas;">Name</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">=</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">ArticleByLine</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> </span></span><span style="color: red; font-family: Consolas;"><span style="color: red; font-family: Consolas;">Hidden</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">=</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">TRUE</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> /></span></span><br />
<span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">
<span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"></span></span></span></span><br />
<span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> <</span></span><span style="color: #a31515; font-family: Consolas;"><span style="color: #a31515; font-family: Consolas;">RemoveFieldRef</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> </span></span><span style="color: red; font-family: Consolas;"><span style="color: red; font-family: Consolas;">ID</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">=</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">{d3429cc9-adc4-439b-84a8-5679070f84cb}</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> </span></span><span style="color: red; font-family: Consolas;"><span style="color: red; font-family: Consolas;">Name</span></span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">=</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">ArticleByLine</span></span><span style="font-family: Consolas;">"</span><span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;"> /></span></span><br />
<span style="color: blue; font-family: Consolas;"><span style="color: blue; font-family: Consolas;">
</span></span><span style="font-family: Consolas;"></span></span></span>whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-64887547878052542512011-09-13T14:47:00.000-07:002011-09-13T14:47:54.984-07:00Shrinking the SharePoint Log FIle (for dev machines)Found some useful information on taming a large log file - useful on a SharePoint development machine.<br />
<br />
To shrink log files in sql server 2008, first change the recovery model of database to simple, then shrink the log file and finally change back to the previous recovery model. Here is the SQL:<br />
<div>
<br />USE dbname;</div>
<div>
<div>
GO</div>
<div>
-- Truncate the log by changing the database recovery model to SIMPLE.</div>
<div>
ALTER DATABASE dbname</div>
<div>
SET RECOVERY SIMPLE;</div>
<div>
GO</div>
<div>
-- Shrink the truncated log file to 1 MB.</div>
<div>
DBCC SHRINKFILE (2, 1); -- here 2 is the file ID for trasaction log file,you can also mention the log file name (dbname_log)</div>
<div>
GO</div>
<div>
-- Reset the database recovery model.</div>
<div>
ALTER DATABASE dbname</div>
<div>
SET RECOVERY FULL;</div>
<div>
GO</div>
<div>
</div>
<div>
Thanks to <a href="http://social.msdn.microsoft.com/Forums/en/sqldatabaseengine/thread/54e6e281-005a-4b07-8c85-3685441f4f3d">an answer</a> by RTTAdmin on the MSDN forums for that suggestion.</div>
</div>
whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0tag:blogger.com,1999:blog-5760703966775804012.post-24550863936762819782011-09-12T14:03:00.000-07:002011-09-12T14:03:23.361-07:00SharePoint 2010 Timer Job Journey of Discovery - Updating Web App PropertiesSo there I was, creating a SharePoint 2010 Timer Job to retrieve and aggregate tag information from the Social Data Service. Using a pattern that worked well in SharePoint 2007, the feature receiver in the solution was tailored to save information for each execution of the job to the property bag of the web application.<br />
But the timer job failed to register when activating this solution through the features admin page on the site. The event log showed an "Access denied" SecurityException error, occuring in the call to SPWebApplication.Update(). The code was simply attempting to set a web application property at that stage.<br />
<br />
Time passes... Lots of experimentation and research.... Finally discovered the cause is related to applying least privileges access to accounts on the server install. The account under which the feature gets activated when clicking on "Activate" in the browser UI does not have sufficient rights to make changes in the configuration database. And web application property bag settings seem to be saved to the configuration database rather than to a content database (makes sense, I guess, as a web app can be associated with multiple content databases).<br />
<br />
The solution therefore is to activate the feature using PowerShell whilst logged in with an account having update rights on the config database - for instance, using the setup account (which you used during installation, of course, didn't you?!)whats.to.learn.todayhttp://www.blogger.com/profile/06525868686626493995noreply@blogger.com0