tag:blogger.com,1999:blog-9635319209400675652024-03-08T12:34:02.992+01:00My code storiesMix of Power Platform, web programming, .Net, Qt/C++ etc. Your everyday pink tech-blog ;)
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.comBlogger41125tag:blogger.com,1999:blog-963531920940067565.post-22139616878231637742023-12-20T15:31:00.001+01:002023-12-20T15:31:25.357+01:00Power Pages Manifest Explained related to Collaborative Development and ALM<b>In the Microsoft Power Pages, understanding the nuances of configuration files like the `manifest.yml` and environment-specific manifests (e.g., `dev.crm4.dynamics.com-manifest.yml`) is crucial. These files play a significant role in managing and deploying Power Pages sites, particularly in collaborative and ALM contexts.</b><br /><br /><div><h2 style="text-align: left;">Understanding the Manifest.yml File</h2></div><div>First of all, always refer to the <a href="https://learn.microsoft.com/en-us/power-platform/developer/cli/reference/powerpages">official documentation</a> on how the power platform cli tool is supported.<br /><h3 style="text-align: left;">Creation and Usage</h3><b>Creation</b>: The manifest.yml is generated through the<i><b> pac powerpages download </b></i>command. It serves as a snapshot of the Power Pages site's configuration, capturing details like page templates, form settings, and access permissions.<br /><br />Example: When you run this command, it creates a manifest.yml file that includes details of all the components such as web forms, entity lists, and site settings configured in the Power Pages site.<br /><br /><b>Usage</b>: The <b><i>pac powerpages upload</i></b> command utilizes the manifest.yml file to update the Power Pages site. This ensures that any changes made locally by you or your fellow developers are accurately reflected in the online environment.<br /><br />Example: After modifying a page template or adding a new web form locally, you can use this command to upload these changes to the main site.<br /><br /><h3 style="text-align: left;"><br />Comprehensive Components Breakdown</h3><p style="text-align: left;">The `manifest.yml` file includes a wide range of components, each vital to different site functionalities:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li><b>adx_ad</b> and <b>adx_adplacement</b><br /><i>These components are integral to advertising on a website. adx_ad refers to the actual advertisement itself, like a promotional banner or a sidebar ad. It defines the ad's content, dimensions, and other characteristics. adx_adplacement, on the other hand, specifies where on the website the advertisement will be displayed, such as on the homepage, in a sidebar, or between blog posts. This dual structure allows for flexibility in managing both the content and placement of ads.</i></li><li><b>adx_blog</b> and <b>adx_blogpost</b><br /><i>adx_blog represents the overall blog section of a website. It could be a dedicated area for company news, industry insights, or educational content. adx_blogpost refers to individual articles or blog posts within that section. This separation enables effective management of the blog as a whole and the individual pieces of content within it, which is crucial for content marketing and user engagement.</i></li><li><b>adx_botconsumer</b><br /><i>This component integrates chatbot functionalities into the website. A chatbot, like a customer service bot, can be placed on different pages (such as the contact page) to assist visitors by providing information, answering queries, or guiding them through the website. This enhances user experience and engagement.</i></li><li><b>adx_communityforum</b> and <b>adx_communityforumaccesspermission</b><br /><i>These manage the user forums on the website. adx_communityforum is about the creation and maintenance of the forum itself, where users can interact, discuss products, or provide feedback. adx_communityforumaccesspermission deals with setting different levels of access within these forums, like special permissions for staff members or restrictions for certain user groups, ensuring a structured and secure community environment.</i></li><li><b>adx_contentsnippet<br /></b><i>This component handles reusable content blocks across the website, such as headers, footers, or sidebars. For example, a footer snippet might contain contact information, social media links, or legal disclaimers that are consistent across all pages of the website.</i></li><li><b>adx_entityform</b> and <b>adx_entityformmetadata</b><br /><i>These components are crucial for integrating web forms with CRM (Customer Relationship Management) systems. adx_entityform links a web form to a CRM entity, enabling data collection directly into the CRM. adx_entityformmetadata defines the properties and layout of these forms, like fields, labels, and validation rules.</i></li><li><b>adx_entitylist<br /></b><i>It displays lists of records from CRM entities in an organized format on the website. This can be used to show a product catalog, customer testimonials, or any other data stored in the CRM in a structured and user-friendly manner.</i></li><li><b>adx_entitypermission</b><br /><i>This controls who has access to what data in the CRM system. It's essential for data security and privacy, ensuring that sensitive information like customer data is only accessible to authorized user roles.</i></li><li><b>adx_forumthreadtype<br /></b><i>This categorizes forum threads, helping to keep the forums organized. Different thread types might include support queries, product discussions, or general community chat, making it easier for users to find and participate in relevant conversations.</i></li><li><b>adx_pagetemplate<br /></b><i>Provides templates for various web page layouts, ensuring consistency in design across the site. This could include templates for product pages, blog posts, or landing pages.</i></li><li><b>adx_poll</b>, <b>adx_polloption</b>, and <b>adx_pollplacement</b> <br /><i>These components collectively manage interactive polls on the website. adx_poll is the actual poll, adx_polloption are the choices available in the poll, and adx_pollplacement decides where the poll appears on the site, like on the homepage or within a blog post.</i></li><li><b>adx_portallanguage</b> and <b>adx_websitelanguage<br /></b><i>They manage the different language options available for the website, enabling the site to cater to a diverse, multinational audience. This could involve translating the site into multiple languages like English, Spanish, or French.</i></li><li><b>adx_publishingstate<br /></b><i>Controls the various stages of content publishing, from drafting to going live. This is particularly useful for managing blog posts or news articles, allowing for content to be reviewed and approved before publication.</i></li><li><b>adx_redirect</b> and <b>adx_urlhistory<br /></b><i>These components manage URL redirections and track historical URL changes. adx_redirect’ is used for redirecting old URLs to new ones, ensuring users don't encounter dead links, while adx_urlhistory` keeps a record of these changes.</i></li><li><b>adx_shortcut</b> and <b>adx_sitemarker<br /></b><i>Create quick navigation shortcuts and mark specific locations on the site. This can enhance user experience by providing easy access to frequently visited pages like user accounts or checkout pages.</i></li><li><b>adx_sitesetting<br /></b><i>Sets global configurations for the site, like themes, API keys, or other site-wide settings. This could include integrating external services like Google Maps or configuring global SEO settings.</i></li><li><b>adx_tag<br /></b><i>Manages the tagging of content, like blog posts or products, to improve organization and searchability. Tags help users and search engines find relevant content more easily.</i></li><li><b>adx_webfile<br /></b><i>Handles files used on the website, including images, documents, and downloadable content. This is crucial for managing multimedia content and resources like product brochures or user manuals.</i></li><li><b>adx_webform</b>, <b>adx_webformmetadata</b>, and <b>adx_webformstep<br /></b><i>Together, these manage the creation and configuration of web forms and their individual steps. This could include registration forms, contact forms, or feedback forms, with multiple steps for user interaction.</i></li><li><b>adx_weblink</b> and <b>adx_weblinkset<br /></b><i>Manage hyperlinks and groups of links on the site. This is important for navigation, linking to internal pages, or external resources.</i></li><li><b>adx_webpage</b> and <b>adx_webpageaccesscontrolrule<br /></b><i>Represent individual web pages and their access control. This can be used to create members-only areas or restricted content pages.</i></li><li><b>adx_webrole<br /></b><i>Defines various user roles and permissions on the site, like 'Administrator', 'Editor', or 'Subscriber', each with different levels of access and control.</i></li><li><b>adx_website</b>, <b>adx_websiteaccess</b>, and <b>adx_websitebinding<br /></b><i>These capture the overall configuration of the website and manage access to it. This includes settings for the main and backup domains and other site-wide settings.</i></li><li><b>adx_webtemplate<br /></b><i>Provides templates for dynamic content, allowing for standardized yet customizable displays of user-generated content or other dynamic elements.</i></li><li><b>Annotation<br /></b><i>Adds notes or comments to CRM records, facilitating better tracking and management of customer interactions, follow-ups, and internal communications.</i></li></ul>Each of these components plays a vital role in the functionality and user experience of a CRM-integrated website. They allow for a high degree of customization and efficiency in managing different aspects of the site, from content to user interactions. <br /><br /></div><div><b><u>Now it is important to keep in mind that this file is not for you to change. The content is the result of the entire configuration of your site. You still need to maintain the different settings in their right context. <br /></u></b><br /><h2 style="text-align: left;">Collaborative Development Practices</h2><div>The manifest.yml file plays a critical role when multiple developers and contributors are working on the same environment.</div><h3 style="text-align: left;">Version Control Integration:</h3><div><b>Function</b>: The manifest.yml is incorporated into version control systems (like Git) to track changes in the site's configuration.</div><div><b>Benefits</b>: This helps in keeping a historical record of who made what changes and when. It allows multiple developers to work on different parts of the site simultaneously without losing track of the overall progress.</div><div><b>Example</b>: Developer A modifies the adx_webform component while Developer B works on adx_entitylist. Both sets of changes are tracked and merged, ensuring that the final configuration reflects both developers' contributions.</div><h3 style="text-align: left;">Conflict Resolution:</h3><div><b>Function</b>: When changes from different developers conflict (e.g., two developers alter the same component), the manifest.yml file helps identify these conflicts.</div><div><b>Benefits</b>: It simplifies the process of resolving these conflicts by providing a clear view of where the discrepancies lie.</div><div><b>Example</b>: If both developers modify the same adx_webpage settings in different ways, the conflict is highlighted during the merge process, prompting a resolution before final integration.</div><h3 style="text-align: left;">Consistent Development Environments:</h3><div><b>Function</b>: By using the manifest.yml file, teams ensure that all developers work with the same configurations.</div><div><b>Benefits</b>: This consistency reduces the risk of environment-specific bugs and discrepancies, ensuring that the site functions uniformly for all developers.</div><div><b>Example</b>: The manifest.yml ensures that all developers have the same adx_sitesetting values, preventing issues that could arise from differing configurations.</div><div><br /></div><h2 style="text-align: left;">Application Lifecycle Management (ALM) Integration</h2><div>ALM in Power Pages involves managing the site's lifecycle from development through testing to production.</div><h3 style="text-align: left;">Consistency Across Environments:</h3><div><b>Function</b>: The manifest.yml file ensures that configurations remain consistent across different stages of the development lifecycle.</div><div><b>Benefits</b>: This consistency is crucial for smooth transitions between development, testing, and production environments, reducing the likelihood of environment-specific issues.</div><div><b>Example</b>: The same adx_pagetemplate configurations used in development are carried over to testing and production, ensuring uniformity.</div><h3 style="text-align: left;">Automated Deployments:</h3><div><b>Function</b>: In CI/CD pipelines, the manifest.yml file can be used to automate the deployment process.</div><div><b>Benefits</b>: This automation streamlines deployments, making them faster and reducing the potential for human error.</div><div><b>Example</b>: When changes are pushed to a repository, a CI/CD pipeline automatically deploys these changes to the testing environment using the manifest.yml file.</div><h3 style="text-align: left;">Change Tracking and Rollbacks:</h3><div><b>Function</b>: The manifest.yml assists in tracking changes over time and facilitates rollbacks if needed.</div><div><b>Benefits</b>: If a new update introduces issues, teams can quickly revert to a previous, stable configuration.</div><div><b>Example</b>: If a new adx_webrole configuration leads to access issues, developers can revert to an earlier version of the manifest.yml that had the stable settings.</div><h2 style="text-align: left;">In general...</h2><div>The manifest.yml and environment-specific manifest files are foundational for effective Power Pages site management. They enable efficient and collaborative development, ensure consistency across different stages of the development lifecycle, and integrate seamlessly into ALM processes. Understanding these files' structures, uses, and components is key to managing Power Pages projects successfully.</div></div>Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-16392157381302945592023-07-11T08:50:00.003+02:002023-07-11T08:52:52.712+02:00Filtering Dropdown choices in a Power Pages form using Dataverse Relations<h1 style="text-align: left;">Filter dropdowns</h1><div><br /></div>Dropdown filters are a useful feature in form design, allowing users to filter options in one dropdown based on other selections in the form. In Power pages, leveraging the capabilities of Dataverse relations makes it possible to create these powerful filtering mechanisms. This is how it works.<br /><br /><h3 style="text-align: left;">What you need to know first.</h3><div>Before we dive into the implementation details, ensure that you have a basic understanding of Power Pages forms and Dataverse relations. </div><div><br /></div><div><h2 style="text-align: left;">How is´t made</h2><ol style="text-align: left;"><li>Create two tables in your Dataverse environment: "Type" and "Category." These tables will hold the relevant data for the dropdowns.</li><li>Establish a Lookup Relationship between the "Category" and "Type" tables. Create a lookup column in the "Category" table that references the "Type" table. This lookup column will allow us to filter the categories based on the selected type.</li><li>Now, create a third table called "Request." This table will serve as the foundation for the form where you want to implement the filtered dropdown.</li><li>Design the form in Power Pages Designer using the "Request" table as the data source. Add two dropdown controls to the form, one for the "Type" and another for the "Category" field.</li><li>Populate the "Type" table with the available types. E.g. "Individual", "Collective" and "Organization".</li><li>Populate the "Category" table and relate the different categories to types of requests.</li><li>Now go back to the "Request" form in the designer and choose the "Category" control. Check "Filter by related rows" and choose the "Type" table under "Relationship to current table" and select the correct relation name under "Relationship to this lookup´s table".</li><li>Now include the form in a page using the Power Pages Designer. When running the page in preview, it should look something like this.</li></ol><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjDxyI4Dpj2z6IsnBYl53Di4DjLgcLmtKTn7BM_qFysjVEkG8-XKoMuuwYrahusHDo6i1spXnkkzWv1jKw_N3XacOZNZoq6TATV3tiDS2o3hqWV78OvOBerBL_vbwDQxckwWa-URJj2HVdjJv3DtAbhkYuiDoBsvB4254RoWU_EAel4YNL2Y5m0JtLops8" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="658" data-original-width="1381" height="283" src="https://blogger.googleusercontent.com/img/a/AVvXsEjDxyI4Dpj2z6IsnBYl53Di4DjLgcLmtKTn7BM_qFysjVEkG8-XKoMuuwYrahusHDo6i1spXnkkzWv1jKw_N3XacOZNZoq6TATV3tiDS2o3hqWV78OvOBerBL_vbwDQxckwWa-URJj2HVdjJv3DtAbhkYuiDoBsvB4254RoWU_EAel4YNL2Y5m0JtLops8=w596-h283" width="596" /></a></div><div class="separator" style="clear: both; text-align: center;">The type is preselected in this instance, and when opening the lookup, the available items should automatically be filtered.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhUqN2f4hz0NR6KVVabUKZ_-hW7bV7FYohlB2K0BkMCAxc-A2R81vxnonQ-tuB54fsaKaex2XSy0g5kLHPXh7FCmccKHNf24cYyVqcmcQvHIWzAHILxLaGLzBS019TvZEW0kcTQ10X9P0kxTfjMV-7wMb1m4Gzp3pVaVAJHmwEl60kb1z8_J5Gv9G3KFR8" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="615" data-original-width="1227" height="309" src="https://blogger.googleusercontent.com/img/a/AVvXsEhUqN2f4hz0NR6KVVabUKZ_-hW7bV7FYohlB2K0BkMCAxc-A2R81vxnonQ-tuB54fsaKaex2XSy0g5kLHPXh7FCmccKHNf24cYyVqcmcQvHIWzAHILxLaGLzBS019TvZEW0kcTQ10X9P0kxTfjMV-7wMb1m4Gzp3pVaVAJHmwEl60kb1z8_J5Gv9G3KFR8=w618-h309" width="618" /></a></div><br /></div></div>This feature allows you to design effective and easy-to-use forms. After all, your users have other things to do than scrolling through your forms, and I assume that you want quality data ;)</div>Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-9714094280240331982023-06-15T23:59:00.002+02:002023-06-15T23:59:49.561+02:00Exploring the Power of Variables in Liquid and Power Pages <h2 style="text-align: left;">Covering the basics - Variables</h2>
<div>As a templating language, Liquid offers a rich collection of possibilities for web developers and designers, bringing Dynamics business data to the web. Variables in Liquid enable us to display dynamic content and enable us to implement a certain level of custom logic as well. We'll have a look at some examples on how to work with variables.</div>
<h3 style="text-align: left;"><span></span>Variable Assignment</h3>
<div>In Liquid, variables can be assigned values using the <code><b>{% assign %}</b></code> tag. For example, let's assign the value "Hello, Nerd!" to the variable greeting:</div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"> <code style="counter-reset: line 0;">
{% assign greeting = 'Hello, Nerd!' %}
</code><br /></pre>
<h3 style="text-align: left;">Variable Output</h3>
<div>Once a variable is assigned a value, it can be outputted using the <code><b>{{ }}</b></code> syntax. To display the value of greeting, we can use:</div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"> <code style="counter-reset: line 0;">
{{ greeting }}
</code><br /></pre>
<h3 style="text-align: left;">Assigning Site Settings</h3>
<div>Liquid is powerfull enough to allow you to assign values from site settings to variables. For example, if you need the site setting for inactivity for a logged in user before he is automatically logged out, you can assign it to a variable like this.</div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"> <code style="counter-reset: line 0;">
{% assign timeLimit = settings['Authentication/ApplicationCookie/ExpireTimeSpan'] %}
</code><span> </span>{{ timeLimit | escape }}
</pre>
<h3 style="text-align: left;">Assigning User Properties</h3>
<div>You can reach the logged in user properties in your site. For example, if you want to capture the user property for the user's name, you can assign it to a variable like this.</div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"> <code style="counter-reset: line 0;">
{% assign userName = user.fullname %} </code>
</pre>
<h3 style="text-align: left;">Assigning Content Snippets</h3>
<div>Liquid also allows you to assign a content snippet from the selected language to a variable. For example, you have a content snippet called "Account/SignIn/RememberMeLabel" with a translated string, you can assign it to a variable.</div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"> <code style="counter-reset: line 0;">
{% assign RememberMeLabel = snippets["Account/SignIn/RememberMeLabel"] %}
</code><br /></pre>
<h3 style="text-align: left;">Assigning URL Query Strings</h3>
<div>If you have query strings in the URL, you can assign them to variables. This is very usefull when building complex templates relating on the users inputs, like ids, page numbers etc.</div><div><br /></div><div>For example, if you have a query string parameter called "id" in the following </div><div>URL: https://somePowerPagesUrl/somePage/?id=someValueWrittenHere</div><div><br /></div><div>You can then assign its value to a variable like this.</div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;">
{% assign requestId = request.params.id %}
</pre><h3 style="text-align: left;">Iterating Over Arrays</h3>
<div>Liquid allows for looping through arrays using the <code>{% for %}</code> tag. By assigning an array to a variable, you can iterate through its elements and access each item within the loop.</div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"> <code style="counter-reset: line 0;">
{% assign fruits = ['Apple', 'Banana', 'Orange'] %}
{% for fruit in fruits %}
{{ fruit }}
{% endfor %}
</code><br /></pre>
<div>This code will output each element of the fruits array, displaying "Apple," "Banana," and "Orange" sequentially.</div><div><br /></div>
<h3 style="text-align: left;">Conditional Statements</h3>
<div>Liquid supports conditional logic using <code>{% if %}</code>, <code>{% elsif %}</code>, and <code>{% else %}</code> tags. Variables can be used to set conditions and control the flow of the template. </div>
<pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"> <code style="counter-reset: line 0;">
{% if temperature > 30 %}
It's a hot day!
{% elsif temperature < 10 %}
Bundle up, it's chilly!
{% else %}
Enjoy the weather!
{% endif %}</code>
</pre>
<div>In this case, the output will depend on the value of the temperature variable. Based on the value, the template will display the appropriate message.</div>
<h3 style="text-align: left;">Filters</h3>
<div>Liquid filters allow for the modification of variable output. Filters are appended to variables using the <code>|</code> symbol. This comes in very handy when you're converting a variable from one type to another, and making a string URL-friendly.<span style="background-color: green; color: white;"></span></div><pre style="background-color: green; color: white; line-height: 1.5; overflow-x: auto; padding: 10px;"><code style="counter-reset: line 0;">
{{ sentence | capitalize }} </code>
</pre>
<div>In this case, the capitalize filter will convert the first character of the sentence variable to uppercase.</div>
<div><br /></div><h3 style="text-align: left;">So in total</h3><div>Using Liquid variables in Power Pages provide immense flexibility and control over the content and behavior of your templates. This is one of the basic blocks of making Power Pages a full fledged web portal, and not just the sales slides and demos used </div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-36939318602121826452023-06-02T21:41:00.002+02:002023-06-02T21:47:02.350+02:00Enabled Dataverse search in the Microsoft Dataverse environmentSearch is a very powerfull feature when properly configured. Here is a quick step through on how to implement search in Power Pages.<br /><br /><h3 style="text-align: left;">Enable Search in the environment</h3><ul style="text-align: left;"><li>Go to the Power Platform Admin Center. </li><li>Open the administration settings for the Microsoft Dataverse environment and navigate to the search or options settings. </li><li>Enable "Dataverse Search." This needs to be done once for each environment.</li></ul><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRGSNolOVf2WhczzeOgUwCZqgVhTSBF95NNAxUNdUQQ-9mwlNoLZSNx27CvANME55fGN0kVeXMJnEDBEaI4FJmY7fjqiKKiugyrNSi7fDSNKQGlW74VN21oxvtKbQ-bar6nZwiZgiLMpweOKed5ZDZG-knLJt9GBolIfwWhqPMW83EzTu0ZWZz2tFT/s1558/envSearch.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="977" data-original-width="1558" height="386" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRGSNolOVf2WhczzeOgUwCZqgVhTSBF95NNAxUNdUQQ-9mwlNoLZSNx27CvANME55fGN0kVeXMJnEDBEaI4FJmY7fjqiKKiugyrNSi7fDSNKQGlW74VN21oxvtKbQ-bar6nZwiZgiLMpweOKed5ZDZG-knLJt9GBolIfwWhqPMW83EzTu0ZWZz2tFT/w615-h386/envSearch.png" width="615" /></a><br /><br /><h3 style="text-align: left;">Enabled Dataverse search in Power Pages </h3><div><ul style="text-align: left;"><li>Go to Portal Management for the Power Pages site and click on Site Settings. </li><li>Filter the settings for search. </li><li>Make sure that EnableAdditionalEntities, Enabled, and EnableDataverseSearch are set to "true." </li><li>Ensure that the table to be included in the search is included in the filters. </li></ul>Note that tables are listed with the category first, followed by the column and table name. If multiple tables fall under the same category, they should be separated by a comma. <i>Categories with tables are separated by a semicolon. This setting needs to be updated every time the search is expanded to include multiple tables.</i><br /><br /><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPDyC5OG9fdeNtCid4fRxdSI7Y_xHzY_23Oxo03KpbG_hGRvgLw_UeVC1HA_AF8TS4EcOXVSzlV0rdU7QCBMYDgItUfpj6EUHlV_5sEoZ_b2sSjy_LQg-Doqq0t3xwcyhdEwVErKOCzoAhl2qlc9qjmLiH4hxm6IY2plGRe5RU-UWh9DXub_URRArR/s1586/portalmanagementsearchsetings1.png"><img border="0" height="329" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPDyC5OG9fdeNtCid4fRxdSI7Y_xHzY_23Oxo03KpbG_hGRvgLw_UeVC1HA_AF8TS4EcOXVSzlV0rdU7QCBMYDgItUfpj6EUHlV_5sEoZ_b2sSjy_LQg-Doqq0t3xwcyhdEwVErKOCzoAhl2qlc9qjmLiH4hxm6IY2plGRe5RU-UWh9DXub_URRArR/w650-h329/portalmanagementsearchsetings1.png" width="650" /></a></div><br /><h3 style="text-align: left;">Creating a Portal Search View</h3></div><div>To be able to index the columns in each table, we need to create a search view. </div><div><ul style="text-align: left;"><li>Go to <a href="http://make.powerapps.com">make.powerapps.com</a> and find the table for which you want to create a view, then click on "Views."</li></ul><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6dakwX83x5lRId1Bpn-r0Fl_wwQucp2v6GosVqsAnhcJLm3yAb8F5HsZaOz309i0r5J25JJ3m3SBcCNRT_kbq8qxylUi0CwzVGL4Tujk02LG9Y_LG4idiXPTAPO1qGBTap_8R74bTUIaPa-mh2DsRC6augxmeOKcw5aQl8WK1aR2wbPxpBGkWhyFA/s1547/tabellinnstill1.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="643" data-original-width="1547" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6dakwX83x5lRId1Bpn-r0Fl_wwQucp2v6GosVqsAnhcJLm3yAb8F5HsZaOz309i0r5J25JJ3m3SBcCNRT_kbq8qxylUi0CwzVGL4Tujk02LG9Y_LG4idiXPTAPO1qGBTap_8R74bTUIaPa-mh2DsRC6augxmeOKcw5aQl8WK1aR2wbPxpBGkWhyFA/w654-h272/tabellinnstill1.png" width="654" /></a><br /><br /><ul style="text-align: left;"><li>Create a new public view and give it a name that is logical for the search. </li><li>Apply any desired filtering or sorting. </li><li>Once this is done, go back to Portal Management and site settings. </li><li>Set the Search/IndexQueryName to the name of the search view, "Ready Power Pages Search."</li></ul><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkgsJTOFzRCXRsOZuTBVoekFfdisgtY18befA57pLjaCBnTEA8MD0f5CDaaabIbkHeFf0kNsTL2qQrrQ_K6Cesgl6EweuP0tDQeOoGS79ecD2kML4F3YGqtK2AlHcOzbUkZRjkAr9-pFAGxCSqt43Q36vceldzfEr6kNuPvpJVAr7GOuUK_qIkCbD4/s1343/search%20view.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="575" data-original-width="1343" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkgsJTOFzRCXRsOZuTBVoekFfdisgtY18befA57pLjaCBnTEA8MD0f5CDaaabIbkHeFf0kNsTL2qQrrQ_K6Cesgl6EweuP0tDQeOoGS79ecD2kML4F3YGqtK2AlHcOzbUkZRjkAr9-pFAGxCSqt43Q36vceldzfEr6kNuPvpJVAr7GOuUK_qIkCbD4/w645-h276/search%20view.png" width="645" /></a><br /><br /><h3 style="text-align: left;">Enable table permissions</h3></div><div>To allow users to see search results, we need to set access levels for the table and choose which roles should have read access. </div><div><ul style="text-align: left;"><li>Go to <a href="http://make.powerpages.microsoft.com">make.powerpages.microsoft.com</a>, select Set Up -> Table permissions -> create new access and grant Authenticated Users read access.</li></ul><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZPvkbW1GGdTln06BLxTTUq3Fcrl2QXx1LCDNJQPTyBmBqHDY83yTE3nQomsigDF6XrStB-Q0O97p0e33Bp4H5alD38_95MO7vSmw7ES6_wRAJ4D0gJsABreHn2kfOUyyYPP6U9peSWNktHCN6IX7kKSkooAnDivmMfjwPLgPKII0hcjFK2S5rbXGg/s1446/accesslevel.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="749" data-original-width="1446" height="333" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZPvkbW1GGdTln06BLxTTUq3Fcrl2QXx1LCDNJQPTyBmBqHDY83yTE3nQomsigDF6XrStB-Q0O97p0e33Bp4H5alD38_95MO7vSmw7ES6_wRAJ4D0gJsABreHn2kfOUyyYPP6U9peSWNktHCN6IX7kKSkooAnDivmMfjwPLgPKII0hcjFK2S5rbXGg/w642-h333/accesslevel.png" width="642" /></a><br /><br /><h3 style="text-align: left;">Create a page to display search results </h3></div><div>If a page to display details of a search result does not already exist, it needs to be created. </div><div><ul style="text-align: left;"><li>Go to <a href="http://make.powerpages.microsoft.com">make.powerpages.microsoft.com</a> and select new page. </li><li>Give the page a name and choose a suitable layout.</li><li>Add a form to the page that will display the result, such as a contact.</li></ul><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD8fdXiv7B0rgj5KvgGohk4BvCTSFBmQL2e3llRxlmuQW0-FkTb1h49rxHNDw6OavxJ4KoiNx287Xng7W_BygDVV5DZZMvklycgJRAsge8-8OkhGf9nvolsVpNNgGlEuACbK113BidXxscejW82zvmp7EOmfj3Hh2crSAEbY7TPxgr-bAhyHPa_-YM/s1173/newform.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="840" data-original-width="1173" height="456" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD8fdXiv7B0rgj5KvgGohk4BvCTSFBmQL2e3llRxlmuQW0-FkTb1h49rxHNDw6OavxJ4KoiNx287Xng7W_BygDVV5DZZMvklycgJRAsge8-8OkhGf9nvolsVpNNgGlEuACbK113BidXxscejW82zvmp7EOmfj3Hh2crSAEbY7TPxgr-bAhyHPa_-YM/w637-h456/newform.png" width="637" /></a><br /><br /><h3 style="text-align: left;">Create a Site Marker for the search result </h3></div><div>To be able to display the result in the search, we need to create a Site Marker for the search result. This holds the page that is chosen to display the result, but most importantly, it needs to be named correctly. In this case, the name should be "contact_SearchResultPage." Therefore, it is the machine name (logical name) of the table, followed by "_SearchResultPage."<br /><br /><div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnRqyWfVvOpA-itXTmnlplTuBk2WSkkgKPCKpYZWWzkCqif0M6N_m3aYZ9VOSv_vKWd6K-BaFtYCMEc8wQU6bEjBVQ7XGg_KyirBBme6ST6qKrv3VaaGL0v8yKDVWIC8GkRwyO0UnYqgLHhLQSYVkeJgAOpuPuzKiPCplUN8B9mJcJ3kQxlk50yySF/s774/sitemarker1.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="266" data-original-width="774" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnRqyWfVvOpA-itXTmnlplTuBk2WSkkgKPCKpYZWWzkCqif0M6N_m3aYZ9VOSv_vKWd6K-BaFtYCMEc8wQU6bEjBVQ7XGg_KyirBBme6ST6qKrv3VaaGL0v8yKDVWIC8GkRwyO0UnYqgLHhLQSYVkeJgAOpuPuzKiPCplUN8B9mJcJ3kQxlk50yySF/w637-h219/sitemarker1.png" width="637" /></a><br /><br /><h3 style="text-align: left;">Further customizations </h3></div><div><a href="https://learn.microsoft.com/en-us/power-pages/configure/search/overview">Here</a> you will find an overview of additional customization options for the search.<br /><br /><h3 style="text-align: left;">Rebuild the search index by restarting the Power Pages website </h3></div><div><ul style="text-align: left;"><li>To reindex: Go to the Power Platform Admin Center and click on Resources -> select the appropriate Power Pages site and choose Restart Site under Site Actions.</li></ul><div class="separator" style="clear: both; text-align: center;"><br /></div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0GwGo6RSqDBTNZCprYo0Sohc7ZQg8btrODUXkuBNnqwzV_j1lcYRa6JQO7dmI9dWf7mdkkvpMYxkl9o6q5u-REln8FYd9WlOzREZ0kSd-MWO0GNfyQrDXlmS3X1sL9y6P7v53RtItRqLKvo1kr9B-QNgCg4NaKv6AIF7P8v-rpWgsUVOrXSR5RrYW/s962/restart.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="514" data-original-width="962" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0GwGo6RSqDBTNZCprYo0Sohc7ZQg8btrODUXkuBNnqwzV_j1lcYRa6JQO7dmI9dWf7mdkkvpMYxkl9o6q5u-REln8FYd9WlOzREZ0kSd-MWO0GNfyQrDXlmS3X1sL9y6P7v53RtItRqLKvo1kr9B-QNgCg4NaKv6AIF7P8v-rpWgsUVOrXSR5RrYW/w659-h352/restart.png" width="659" /></a><br /><div class="separator" style="clear: both; text-align: center;"><br /></div>This should cover what you need to include your tables and entities in your global Power Pages search. :)</div></div><div><br /></div><div>Cheers,</div><div>Morten</div>Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-22880889844726071262023-06-02T21:15:00.003+02:002023-06-02T21:15:55.163+02:00Revitalizing My Developer Blog: Power Pages for Modern Web Development<h2 style="text-align: left;">Welcome back!</h2><div>It has been quite a while since my last blog post on MyCodeStories, but I'm thrilled to announce that I'm finally reviving this blog. As the technology landscape has evolved over the years, so have my interests and areas of expertise. In the next posts, I want to share with you my renewed focus on Power Pages, as well as the exciting opportunities they present for modern web development.<br /><br /><h3 style="text-align: left;">Embracing Power Pages</h3><div>Power Pages, powered by the robust capabilities of Power Platform and Microsoft 365, have gained significant traction in recent years. These pages allow developers to create dynamic, data-driven web experiences without diving into complex code. With a rich set of features and easy integration with various data sources, Power Pages enable developers to rapidly build and deploy websites that cater to specific business needs.<br /><br />Power Pages allow external users to access data, perform actions, and collaborate seamlessly. Whether it's customer portals, partner portals, or employee self-service portals, PowerApps Portals offer many possibilities for streamlining processes and enhancing user experiences.<br /><br /><h3 style="text-align: left;">Advantages of Developing Websites with Power Pages </h3></div><div>Accelerated Development</div><div>With their low-code/no-code approach, Power Pages empower developers to rapidly prototype, build, and iterate on web solutions. This increased development speed translates into shorter time-to-market and faster feedback loops.<br /><br />Seamless Integration</div><div>Power Pages seamlessly integrate with other Microsoft services, such as SharePoint, Dynamics 365, and Azure. This integration allows developers to leverage existing data and processes, eliminating silos and creating cohesive end-to-end solutions.<br /><br />Customizability</div><div>Despite their low-code nature, Power Pages offer extensive customization options. From branding and UI design to implementing complex business logic, developers have the flexibility to tailor these platforms to match their specific project requirements.</div><div><br /></div><h3 style="text-align: left;">Building Engaging Web Experiences</h3><div>Empowering User Interactions</div><div><ul style="text-align: left;"><li>With Power Pages, developers can create user-friendly interfaces that empower users to interact with data, submit forms, view analytics, and collaborate effortlessly.</li><li>Data Visualization and Reporting: Power Pages allow for the seamless integration of Power BI reports and dashboards, enabling users to gain valuable insights and make informed decisions.</li><li>Extending Functionality with Code: Although Power Pages provide powerful capabilities out of the box, developers can extend their functionality by integrating custom code when necessary. This ensures that even the most unique and intricate requirements can be met.</li></ul>As I embark on this exciting journey to revitalize MyCodeStories, I am thrilled to share my newfound passion for Power Pages. This technology have revolutionized web development, making it easier and faster to build dynamic and data-driven websites. </div><div><br /></div><div>Stay tuned for future blog posts where I'll dive deeper into the ins and outs of Power Pages, share tips and tricks, and explore real-world use cases. Let's embark on this modern web development adventure together!</div></div>Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-51618059077399371312015-09-07T10:18:00.002+02:002015-09-07T10:18:15.829+02:00Design an awesome experience! Part four.<div dir="ltr" style="text-align: left;" trbidi="on">
<h1>
Let's get physical</h1>
<div class="MsoNormal">
<div class="MsoNormal">
<span lang="EN-US">Involved in
a service of any kind there will be work that not necessarily is very visible.
Visualizing progress or work behind the scenes or even giving the user some
sort of price or token for using the service creates a more personal
relationship or even feeling of ownership to the service. This boosts loyalty
and the user is most likely to return time and again. <o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="EN-US">Getting
physical would be far easier in a physical world. Now, in this context, the
closest we get to getting physical would be by sending the user a price of
sorts, but that would be expensive and not least – it would be very slow and
taken out of context. What we need is something that would pamper the user and tie
the price to the context, so the user experience some sort of reward for being loyal.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">This is
where we can draw advantage from social gaming, rewarding the user with points
or badges for their activity. By ranking the users by their activities, or even
by their contributions, we can easily achieve service awareness and loyalty. <o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<span lang="EN-US" style="background: white; color: #262626; font-family: "Helvetica",sans-serif; font-size: 10.5pt; line-height: 107%; mso-ansi-language: EN-US;">Therefore, in the context of designing an intranet, we use social gaming
as a mean to boost usage and loyalty. In SharePoint, by creating lists that
keep track of scores and workflows we can award contributions and other
activities, and even keep the history from these events. We trigger activity by
listing ranks and suggesting to the user how to improve his or hers ranking.</span><span lang="EN-US"><o:p></o:p></span><br />
<span lang="EN-US" style="background: white; color: #262626; font-family: "Helvetica",sans-serif; font-size: 10.5pt; line-height: 107%; mso-ansi-language: EN-US;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXk8ZLr8TJHOiI3bd-8J8SgBRzxCv2COP79x1pwtTKSOJbYdCdXrxMfDmTnGDKFmevR17oKvwV5mhBjpfQlwNO8kHuda8fFnlErceONmfIaZWVInFWKzJBFCYzAj2vqxKHqyMJaYXC128/s1600/stack.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXk8ZLr8TJHOiI3bd-8J8SgBRzxCv2COP79x1pwtTKSOJbYdCdXrxMfDmTnGDKFmevR17oKvwV5mhBjpfQlwNO8kHuda8fFnlErceONmfIaZWVInFWKzJBFCYzAj2vqxKHqyMJaYXC128/s400/stack.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<span lang="EN-US" style="background: white; color: #262626; font-family: "Helvetica",sans-serif; font-size: 10.5pt; line-height: 107%; mso-ansi-language: EN-US;">The figure above shows one example on how points, badges etc. can be used as rewards for contributions and service loyalty. The images is a screen dump from my profile at Stackoverflow.com</span></div>
</div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-48586878543941319242015-08-21T11:49:00.000+02:002015-08-31T15:51:02.705+02:00Design an awesome experience! Part three.<div dir="ltr" style="text-align: left;" trbidi="on">
<h1>
<span lang="EN-US"><div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGk3HWSIScuGi4A0u55PDuOQcLgqs_nBWwJcIYRYaMIagtaDVhkhxOrzaGvgvwNpsyCzMtM2Yzl_p8IfDIy8aMDyFYJd7KtKoivcYpKO-qsBuEnNVEGWQITBmfgNScF4YqDVSAghQ3SxM/s1600/designCircle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGk3HWSIScuGi4A0u55PDuOQcLgqs_nBWwJcIYRYaMIagtaDVhkhxOrzaGvgvwNpsyCzMtM2Yzl_p8IfDIy8aMDyFYJd7KtKoivcYpKO-qsBuEnNVEGWQITBmfgNScF4YqDVSAghQ3SxM/s1600/designCircle.png" /></a></div>
<o:p></o:p></span></h1>
<div class="MsoNormal">
<span lang="EN-US"></span></div>
<h2 style="text-align: left;">
<span lang="EN-US">Chunk it up!</span></h2>
<div class="MsoNormal">
<span lang="EN-US">Designing
complex services requires that you fill in all the blanks in the service
journey. Dividing the your design into a preface, main face and post face helps
you focus on what happens before, during and after the user have interacted
with the service.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">The preface
is where the user encounters your service for the first time. You need to ask
questions like; how will the user become aware of the service? What parts of
the service does the user interface with and how are they presented? Does the
service solve the right problems? What is the impression the user is left with
after leaving the service and how likely is it that the user will return?<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4ZINjrQ8bhCY7-yC6mHHrhkZN-2Uo37VBzSA0CUcIQqAts3BpPhdaMVfJjDl6O0vG-qCZzv_owvikvQnkn4AiX8sSWCTEx_2MZfEgA67eSuFP1eQommZ0Qijm8V-8lduyH4_9GTfE7h0/s1600/dia.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4ZINjrQ8bhCY7-yC6mHHrhkZN-2Uo37VBzSA0CUcIQqAts3BpPhdaMVfJjDl6O0vG-qCZzv_owvikvQnkn4AiX8sSWCTEx_2MZfEgA67eSuFP1eQommZ0Qijm8V-8lduyH4_9GTfE7h0/s400/dia.png" width="400" /></a></div>
</div>
<div class="MsoNormal">
<span lang="EN-US">Let us
assume that we have interviewed our stakeholders. Sally from accounting have a
need for registering correct hours before billing the company’s clients. Her
need is to get the system implemented as soon as possible and getting the users
to hand in their hours using the new system instead of handing it in on paper
once a week, as this is optional.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">This means
that we need to think about how to make the employees aware of the service,
make sure that the service is easy to use and collect the right data so that
both the employees and accounting will be satisfied. We want access to the
service to be as easy as possible so a maximum two-click link from the welcome
page is set as a requirement. We want the user to be able to go straight in and
register hours. Integrating the login with the intranet login is one way of
achieving this. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">When the
user have completed registering hours, there should be no further follow-up
required from the employee. Returning to the site should also be a simple
navigation click or swipe. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<br />
<div class="MsoNormal">
<span lang="EN-US">Now, this
is where the system starts working with the data. The employee data must be
reported to accounting so that they can pay the employee salary. In addition to
the hours, accounting need to categorize the hours and assign them different
properties. In addition, there should be an approval feature letting management
reject or approve the hours registered and the explanation given to back them
up. Usually the hour registering is part of a third party application. It is likely
that the registering form is integrated with the accounting application. In
addition, this part might require an integration. For instance, we might need
an integration between the intranet and the accounting system, alerting
management that there are hours that need approving.<o:p></o:p></span></div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-71819873151133176782015-08-21T11:46:00.005+02:002015-08-21T11:50:36.272+02:00Design an awesome experience! Part two.<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGk3HWSIScuGi4A0u55PDuOQcLgqs_nBWwJcIYRYaMIagtaDVhkhxOrzaGvgvwNpsyCzMtM2Yzl_p8IfDIy8aMDyFYJd7KtKoivcYpKO-qsBuEnNVEGWQITBmfgNScF4YqDVSAghQ3SxM/s1600/designCircle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGk3HWSIScuGi4A0u55PDuOQcLgqs_nBWwJcIYRYaMIagtaDVhkhxOrzaGvgvwNpsyCzMtM2Yzl_p8IfDIy8aMDyFYJd7KtKoivcYpKO-qsBuEnNVEGWQITBmfgNScF4YqDVSAghQ3SxM/s1600/designCircle.png" /></a></div>
<h2 style="text-align: left;">
Focusing on the user</h2>
<div class="MsoNormal">
<span lang="EN-US">Our design
focus when designing a service is the user, and how the service journey will
affect the user. Not only must we be able to tell how the service will work and
how the user will interact with it. We also need to think about what happens
before and after the user has interacted with it, what knowledge is required
even to use it, etc.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">To answer
these questions we need to understand the user needs, and how the user will
experience the service. The methods used to acquire these answers might vary
from interviewing the users, observing the user, or experience the service
yourself. The chosen method will differ from time to time. It depends on how
complex the service will be.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">The main
point is that you as a designer create a way to communicate with the user and
map their wishes, desires, requirements etc. Remember that as little as one
extra click or unnecessary text box might make your design quite cumbersome and
difficult to use. I would claim that it is all about respecting your users.
After all, they have better things to do than to spend all their time working
on your bad design. ;)<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<br />
<div class="MsoNormal">
<span lang="EN-US">So, keep it
simple and easy to use. </span></div>
<h3 style="text-align: left;">
Co-creating</h3>
<div class="MsoNormal">
<span lang="EN-US">Already
arguing that service design is not a one-man job, the designer must involve all
relevant stakeholders on the design. Using different methods for the users to
contribute to how the service should be designed not only gives you valuable
data on what the user expect. It also makes change management easier when the
service is deployed. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">My favorite
methods are using touch point cards, permanent markers and a large sheet of
brown paper. Letting the users look at a large amount of pictures and writing
down their immediate associations and thoughts related to the service kicks off
the creative process easily. Drawing up the context on paper and composing
journeys by combining pictures quickly open their eyes to possibilities that
they had not thought of yet, etc. Documenting this process, I usually let
people use their mobile cameras and collect the pictures after the session. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">So, let us
hang on to the hour registry for a few more minutes. The stakeholders for this
service is the employee, management and accounting. Designing this service, I
would bring all three into the design process and bring the stack of touch
point cards. Using the cards, we would collectively design the service journey
by picking out cards representing ideas and documenting the ideas. I have
experienced that one of the most effective ways to create these journeys is to
spread the cards on the paper, drawing and writing keywords and connecting the
dots. Finally documenting simply using the camera on your phone. This helps you
documenting the agreed design before implementing a prototype, and the users
get the feeling that they actually take part in the process, creating their own
tools. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">Therefore,
in one small exercise you have a tool for design and documentation giving you
relevant ideas for the final design, but also a side order of clever change
management. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US">
<span lang="EN-US" style="font-family: "Calibri",sans-serif; font-size: 11.0pt; line-height: 107%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;"><br clear="all" style="mso-special-character: line-break; page-break-before: always;" />
</span>
</span></div>
<div class="MsoNormal">
<br /></div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-89416350548029994392015-08-21T11:04:00.000+02:002015-08-21T11:43:42.418+02:00Design an awesome experience! Part one.<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: left;">
<b>The
methodology behind designing service journeys provides you with great
analytical tools that will fit almost any kind of experience. Working in the
areas of design, development and project management this approach have been
amongst my favorites for many years, but I’ve never taken the time to really document
the way I use it.</b></div>
<div style="text-align: left;">
<b><br /></b></div>
<div class="MsoNormal">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9HqAnBgeXKLXtUCmL8m97W7gK_ivr-uV-omiCJVixIBHUpWk1tLV2DXGkfQPjDaKzhtYNCLo6zyw1zj7KiO02Vu0zZKL4LKWY4fluCbAGujIeqbLECohyHLQPU5QwNh-1ObZQ6q0vxI/s1600/designCircle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9HqAnBgeXKLXtUCmL8m97W7gK_ivr-uV-omiCJVixIBHUpWk1tLV2DXGkfQPjDaKzhtYNCLo6zyw1zj7KiO02Vu0zZKL4LKWY4fluCbAGujIeqbLECohyHLQPU5QwNh-1ObZQ6q0vxI/s1600/designCircle.png" /></a></div>
<span lang="EN-US">Years ago,
I attended a session demonstrating AT-ONEs Touch-point cards, and how simple
images and text can be used to design a service or a service journey. I have
kept my stack of cards and used them in every project I have worked on since. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">The last
few years I have dived into different methodologies and dragged more concepts
into my work as I saw them fit. Now, time is overdue to tie some threads
together and document my work. My next few blog posts are dedicated to this
subject, and I hope that they can be helpful. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US">My context
is based on designing web and intranet experiences, so naturally I will try to
tie up this in my examples. Designing a SharePoint intranet for a medium sized
company will be the case for the series.</span></div>
<h2 style="text-align: left;">
<span lang="EN-US">Service design</span></h2>
<div class="MsoNormal">
<span lang="EN-US">Service
design cross into most disciplines. The service itself forms the very base for the
existence of each discipline in the first place. Why? Because each discipline
in one way or another supports the service being provided. The point being,
leaving service design solely to one person in the organization will not work
so well.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">However,
let us not lose focus on the subject. :) How is this relevant to your company
intranet? <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US">The answer
is really – what goes in your intranet? We define an intranet to be an arena
for collaboration, sharing information and working with documents and
workflows. The users find their tools for registering hours, sharing documents and
for social interaction across the organization. All users will use a portal as
their starting point, and will find their tools and content using search and
navigation.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">In order to
design a coherent experience providing the users with content exceeding the
native functionality of the intranet, we need input from the right people.
Mapping different stakeholders and using them as resources for the design
process helps collecting the input and set the requirements for the design.<o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">So, here’s
the case: <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US">Sally from
accounting want the company’s employees to register their hours using a new
reporting system. Her requirement for the intranet is to provide a link to this
system. The link must be visible and easy to find. Max, the sales manager, want
to check in his hours when he is on the road, connecting via his phone. Pat
from IT, requires that access to the intranet is secure so company confidential
information do not get lost.<o:p></o:p></span></div>
<br />
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">Only
providing a simple service as this shows the necessity of the design properly
thought through. <o:p></o:p></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US"><br /></span></div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-27140450926322633172015-03-27T13:01:00.001+01:002015-03-27T13:02:32.972+01:00Folding map effect using Oridomi<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="MsoNormal">
<span lang="EN-US">Half gob smacked I’ll just throw out one more post today. I’ve discovered <a href="http://oridomi.com/">Oridomi </a>today.
In a matter of minutes, I was able to add a cool feature to my page. <o:p></o:p></span><br />
<span lang="EN-US"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOKqVKZQAvVwPBa8FyjyjY05olh688KMeiRRYzXTtXrw-wpRVZyoh45NAmHa4LoxYN-_Z6_2vPDTM5n-EcT6zFwhmhP8l4GxeD4AptjGg3YGLYP8yiIZ3dIlY5F07WVv_nqE6psK0NUAU/s1600/Untitled+picture3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOKqVKZQAvVwPBa8FyjyjY05olh688KMeiRRYzXTtXrw-wpRVZyoh45NAmHa4LoxYN-_Z6_2vPDTM5n-EcT6zFwhmhP8l4GxeD4AptjGg3YGLYP8yiIZ3dIlY5F07WVv_nqE6psK0NUAU/s1600/Untitled+picture3.png" height="320" width="166" /></a></div>
<span lang="EN-US"><br /></span></div>
<div class="MsoNormal">
<span lang="EN-US">First, I
added a static Google Map image to my page using the Google Map API for
position and markers. <o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<pre class="brush: html">var customShapes = [];
<div class="myoridommi">
<img src="https://maps.googleapis.com/maps/api/staticmap?center=59.273544,11.096837&zoom=15&size=600x400&markers=color:blue%7C59.273544,11.096837&maptype=hybrid" />
</div>
</pre>
<div class="MsoNormal">
<span lang="EN-US">Then I put
this image inside a div element that when executed folds the map up like a…
yes, map ;)<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<br />
<div class="MsoNormal">
<span lang="EN-US">Check out
the code…<o:p></o:p></span></div>
</div>
<pre class="brush: javascript">var customShapes = [];
var oriDomi = new OriDomi('.myoridommi', {
vPanels: 5, // number of panels when folding left or right (vertically oriented)
hPanels: 3, // number of panels when folding top or bottom
speed: 3200, // folding duration in ms
ripple: 2, // backwards ripple effect when animating
shadingIntesity: .5, // lessen the shading effect
perspective: 800, // smaller values exaggerate 3D distortion
maxAngle: 40, // keep the user's folds within a range of -40 to 40 degrees
shading: 'soft' // change the shading type
});
var unfolded = false;
function effect() {
// unfolded ? jQuery(".myoridommi").hide() : jQuery(".myoridommi").slideToggle(500);
unfolded ? oriDomi.foldUp() : oriDomi.unfold();
unfolded = !unfolded;
}
effect();
document.getElementById('CanvasLoc').addEventListener('click', effect);
...
...
</pre>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-28788084982658588322015-03-27T10:39:00.001+01:002015-03-27T10:39:30.969+01:00Fetching blogger posts using ajax.<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
For my showcase webpage, I wanted to show some of my blog posts as a demo. Now getting hold of rss-content is fairly easy in an rss-reader; but as JavaScript objects – not so much.<br />
<br />
I came across different pieces and put them together in a solution that gave me a limited number of blog posts as JavaScript objects using ajax and the blogger API.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEUpwe7aZUq9EI0W9ZvVCbWduA8p33ZNRwjag3dD0zeKnM03n69UD0bUI0erM1qdyQxrhZ9L4gHGovXPevVjhoF6NNcZ6hAgo-10f6MEHRzmvZe5VptZraDeMOnjKyxVWQh3OiRIsB468/s1600/Untitled+picture2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEUpwe7aZUq9EI0W9ZvVCbWduA8p33ZNRwjag3dD0zeKnM03n69UD0bUI0erM1qdyQxrhZ9L4gHGovXPevVjhoF6NNcZ6hAgo-10f6MEHRzmvZe5VptZraDeMOnjKyxVWQh3OiRIsB468/s1600/Untitled+picture2.png" height="176" width="320" /></a></div>
<br />
<br />
In the following snippet, I fetch the data using ajax and handle the response building an array of blog posts.
Please see my inline comments...
<br />
<br /></div>
<pre class="brush: javascript">var customShapes = [];
// First I need a container holding the data in a structured way. As I render the content, I traverse through the array handling each object
var blogPosts = [];
...
// As the query will change in different scenarios I keep part of the query string as an argument in the function call.
loadBlogPostAndRender('alt=json-in-script&start-index=1');
...
...
function loadBlogPostAndRender(posts) {
$.ajax({
url: 'http://www.someBloggerBlogUrl/feeds/posts/default?' + posts, // The blog url and the variable specifying the query arguments
type: 'get',
dataType: "jsonp", // It is VERY important that you use jsonp and not json to get around cross site scripting restrictions
success: function (data) {
try {
var posturl = ""; // Initiating variables
var postcontent = "";
var postCat = "";
// Traversing the responce handling each post
for (var i = 0; i < data.feed.entry.length; i++) {
// Getting the post url
for (var j = 0; j < data.feed.entry[i].link.length; j++) {
if (data.feed.entry[i].link[j].rel == "alternate") {
posturl = data.feed.entry[i].link[j].href;
break;
}
}
// Fetch tags from the blog post
for (var k = 0; k < data.feed.entry[i].category.length; k++) {
postCat = data.feed.entry[i].category[k].term + " ";
}
// Fetching the content
if ("content" in data.feed.entry[i]) {
postcontent = data.feed.entry[i].content.$t;
} else if ("summary" in data.feed.entry[i]) {
postcontent = data.feed.entry[i].summary.$t;
} else {
postcontent = "";
}
// As I want to show any image from the blog post as well, I look for the first image linked up to the blog post.
var imgUrl = "";
try {
imgUrl = $(data.feed.entry[i].content.$t).find('img:first').attr('src');
} catch (error) {
imgUrl = "http://foo.com/missingimage.png"; // If there is no image, I keep a placeholder backup
}
// As I only need part of the blog post, I use regular expressions to filter the content and substring to limit the length.
var re = /<\S[^>]*>/g;
postcontent = postcontent.replace(re, "");
//reduce postcontent to 200 characters
if (postcontent.length > 200) {
postcontent = postcontent.substring(0, 400);
}
// Getting the title and publication date.
var posttitle = data.feed.entry[i].title.$t;
var postdate = data.feed.entry[i].published.$t;
// I'm done and add the content as an object on to the array.
blogPosts.push({ bUrl: posturl, bTitle: posttitle, bContent: postcontent, bDate: postdate, bCategory: postCat, bImgUrl: imgUrl });
}
} catch (e) {
}
},
error: function () {
// writeErrorMessage("blogCanvas");
},
complete: function () {
// When the request is complete it is time to render the content.
listAll(blogPosts);
// In order to start the next request with a clean slate, I empty the array.
blogPosts = [];
}
});
}
...
...
...
</pre>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-78558753019033681242015-03-27T10:02:00.002+01:002015-03-27T10:39:59.199+01:00Execute Canvas rendering based on scroll event.<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
I have been showing animations using canvas in several blog posts lately and implemented a lot of this in my own homepage. Now, if you are doing animations you need to plan how the animations should execute so that the user does not miss the whole show. :)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUSJzcRG_7nGWNPdYOiH8h5kZ0N30PMpoPGjDysgaOSe_7BBJ9MnH0CzQ29Qnj54CE2OUD84zsG_jFjRJyrFQozkqvTDF8CU_Q9FUfD0KnbeLfdKgov5kgDvR2QVTZ4mFYn6nWRN2F3Rk/s1600/Untitled+picture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUSJzcRG_7nGWNPdYOiH8h5kZ0N30PMpoPGjDysgaOSe_7BBJ9MnH0CzQ29Qnj54CE2OUD84zsG_jFjRJyrFQozkqvTDF8CU_Q9FUfD0KnbeLfdKgov5kgDvR2QVTZ4mFYn6nWRN2F3Rk/s1600/Untitled+picture.png" height="320" width="202" /></a></div>
<br />
You might want to kick off the animation on a click, or even on a long page – start the animation once the user scrolls down to the animations position. There would be little use in an animation if the show were over when the user gets to it, right?<br />
<br />
Now, you can hook on to the browsers events using the window object or the document object. The click event I’ve already covered in this <a href="http://mycodestories.blogspot.no/2015/01/create-interactive-html5-canvas-using.html">post</a>.
For the scroll event you need to grab the window object.<br />
<br />
The easiest way to do this is to use JQuery and extend the scroll event. In this example I’ve added a delay before kicking of the animation.<br />
<br />
I’ve also calculated the position the user should scroll to before firing the event handler.
</div>
<pre class="brush: javascript">var target = $("#mainSectionFootprint").offset().top - 400,
timeout = null;
$(window).scroll(function () {
if (!timeout) {
timeout = setTimeout(function () {
clearTimeout(timeout);
timeout = null;
if ($(window).scrollTop() >= target) {
startFootLoop();
}
}, 250);
}
});
</pre>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-83018355003159304162015-03-20T14:20:00.001+01:002015-03-23T10:25:24.747+01:00Resizing your canvas drawings properly using repaint<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
This post will be a short one attending a problem I briefly touched upon in my previous post on animation using canvas. We live in a "mobile first" world and need to pay attention to responsive designing.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf0wEbrFVqD_3GLKtMcJhyphenhyphen186O6BeOPWsb0Y6SOWD7uogmLzZMk4NkRWC6M-MLDJ5WrNmEg519PypFsqMx6z1Fz_UW2ut5JRsge0w3Y5dMe9zYFvugsO__M7EGvF9eAMqwV2LYOUKEqnc/s1600/myc.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf0wEbrFVqD_3GLKtMcJhyphenhyphen186O6BeOPWsb0Y6SOWD7uogmLzZMk4NkRWC6M-MLDJ5WrNmEg519PypFsqMx6z1Fz_UW2ut5JRsge0w3Y5dMe9zYFvugsO__M7EGvF9eAMqwV2LYOUKEqnc/s1600/myc.png" height="287" width="320" /></a></div>
<br />
<br />
Try as you might resizing your canvas using CSS you are in for a disappointing surprise. Especially if you are rendering text, it will look all chunky and broken.
My solution to this problem is to calculate a factor value based on the window and canvas width. Using this value, I can multiply it with all xes and ys and lengths and widths and so on and keep the relative positions all these shapes have to each other.
</div>
<pre class="brush: javascript">var ic = window.innerWidth / (canvas.width * 1.2) > 1 ? 1 : window.innerWidth / (canvas.width * 1.2);
</pre>
<div class="separator" style="clear: both; text-align: left;">
When adding objects I apply the factor to keep the relative positions.
</div>
<pre class="brush: javascript">var customShapes = [];
// Figures - Balls
customShapes.push({ x: ic * (canvas.width / 2 - 58), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 - 152), borderThickness: ic * (11), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 2.4 });
customShapes.push({ x: ic * (canvas.width / 2 - 117), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 - 102), borderThickness: ic * (3), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 3 });
customShapes.push({ x: ic * (canvas.width / 2 + 43), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 - 150), borderThickness: ic * (7), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 1 });
...
...
...
</pre>
Now, make sure to use the windows.resize event to kick off the rerendering of your canvas. The result is a world apart from the CSS approach.</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-83258439371062097252015-03-20T14:04:00.003+01:002015-03-20T14:25:40.152+01:00Animating objects using HTML5 Canvas<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: left;">
Object animation using JavaScript is fairly simple once you get the hang of it. In the three previous posts I've explained how to render shapes and how to render a series of shapes. To recap some of the steps I've included the part where I create the objects.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXwoz9Bm3pyFygKRq74xoHo-5YMpyWGqT6ywzFLyzH-OcbLNplDCA_is2HMX7IexoZ_5KFD00rPzQpI9G9Bee_jwrByJpvdlg1LPFxAIi0KdCUF4t07oaJttrkVvhk4Jm7qOYj-MJ_SR4/s1600/shapes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXwoz9Bm3pyFygKRq74xoHo-5YMpyWGqT6ywzFLyzH-OcbLNplDCA_is2HMX7IexoZ_5KFD00rPzQpI9G9Bee_jwrByJpvdlg1LPFxAIi0KdCUF4t07oaJttrkVvhk4Jm7qOYj-MJ_SR4/s1600/shapes.png" height="81" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="clear: both; text-align: left;">
Creating classes</h3>
<div class="separator" style="clear: both; text-align: left;">
I've created a generic shape class called CShape, with a set of basic properties that I find relevant for any of the shapes I'm going to render. This also includes properties relevant to animation. Each property is explained in the comments below.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript">// Applies to circles, boxes and lines
// X and Y coordinates
// expand (bool) growing (true) or shrinking (false)
// direction - animating going cw or ccw
// speed - animation speed
// borderThickness - border thickness
// borderColor - border color
// color - shape color
// clickZone - clickable zone with pointer cursor
// speed - animation speed
function CShape() {
this.x = 0;
this.y = 0;
this.expand = true;
this.speed = 0;
this.borderThickness = 1;
this.borderColor = "#FFFFFF";
this.color = "#000000";
this.delay = false;
this.runAnimation = false;
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Further on I've extended the CShape creating another class called CCircle. Here I've added the properties minRaduis and maxRadius as these only apply to circular shapes. The radius values will be used for animating references, growing or shrinking.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript">CCircle.prototype = new CShape();
CCircle.constructor = CCircle;
// Circle object - prototyped CShape
// Adds min and max radius.
function CCircle() {
this.minRadius = 0;
this.maxRadius = 0;
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
A bit to the side, but indeed relevant to the mission we add a factor for resizing. You might know that resizing a canvas without rerendering the content might give you a poor result, so we'll do a calculation here and multiply all positions and sizes with it. I'll come back to this in a future blog post. Maybe even the next.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript">var ic = window.innerWidth / (canvas.width * 1.2) > 1 ? 1 : window.innerWidth / (canvas.width * 1.2);
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="clear: both; text-align: left;">
Creating objects</h3>
<div class="separator" style="clear: both; text-align: left;">
Now I am ready to create some shapes. For this demo I'll create a series of small circles like you can see on my home page. I add them straight away to the array to save some steps, but you can create the objects based on the classes and then add them later if you wish.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript">var customShapes = [];
// Figures - Balls
customShapes.push({ x: ic * (canvas.width / 2 - 58), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 - 152), borderThickness: ic * (11), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 2.4 });
customShapes.push({ x: ic * (canvas.width / 2 - 117), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 - 102), borderThickness: ic * (3), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 3 });
customShapes.push({ x: ic * (canvas.width / 2 + 43), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 - 150), borderThickness: ic * (7), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 1 });
customShapes.push({ x: ic * (canvas.width / 2 + 138), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 - 120), borderThickness: ic * (15), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 1.4 });
customShapes.push({ x: ic * (canvas.width / 2 + 195), minRadius: 0, maxRadius: ic * (3), y: ic * (canvas.height / 4 + 53), borderThickness: ic * (10), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 4 });
customShapes.push({ x: ic * (canvas.width / 2 + 99), minRadius: 0, maxRadius: ic * (2), y: ic * (canvas.height / 4 + 152), borderThickness: ic * (6), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 1.4 });
customShapes.push({ x: ic * (canvas.width / 2 - 75), minRadius: 0, maxRadius: ic * (2), y: ic * (canvas.height / 4 + 232), borderThickness: ic * (26), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 2.9 });
customShapes.push({ x: ic * (canvas.width / 4 + 60), minRadius: 0, maxRadius: ic * (2), y: ic * (canvas.height / 4 + 86), borderThickness: ic * (12), borderColor: ringBlue, color: ringBlue, runAnimation: !0, speed: 5.4 });
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="clear: both; text-align: left;">
Rendering shapes</h3>
<div class="separator" style="clear: both; text-align: left;">
Now it is time for some logic. We need a function that can render a circle based on these objects. The function below takes an object, an id and the canvas context as an argument. I choose to send in the context because I want to use the same function rendering on several canvas elements in one page.
Other than that the function pretty much does what it says.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript">// Renders a circle based on a Circle object
function drawCircle(tmpShape, id, renderContext) {
var tmpCircle = new CCircle();
tmpCircle = tmpShape;
var centerY = tmpCircle.y;
var centerX = tmpCircle.x;
// These two lines are relevant to the rendering speed. </pre>
<pre class="brush: javascript">// As long as the minRadius is less than the maxRadius it
// will grow according the the value of the speed property
if (tmpCircle.minRadius <= tmpCircle.maxRadius) {
tmpCircle.minRadius = tmpCircle.minRadius + tmpCircle.speed;
}
var radius = tmpCircle.minRadius;
renderContext.fillStyle = tmpCircle.color;
renderContext.lineWidth = tmpCircle.borderThickness + (tmpCircle.minRadius * 0.01);
renderContext.strokeStyle = tmpCircle.borderColor;
renderContext.save();
renderContext.beginPath();
renderContext.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
renderContext.fill();
renderContext.stroke();
renderContext.restore();
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3 style="clear: both; text-align: left;">
Animating the shapes</h3>
<div class="separator" style="clear: both; text-align: left;">
Oki, so now we can draw a circle. Now I'll add two functions. One for running the rendering based on the kind of shape, and one that runs through the array.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript">// Loops through the custom shape array calling renderShapes on every shape
function animationLoop() {
var i = customShapes.length;
while (i-- && i >= 0) {
var customShape = customShapes[i];
// Calling the rendering function
renderShapes(customShape, i, context);
if (customShapes[20].minRadius >= customShapes[20].maxRadius) {
//checking if the shape should continue animating in the next iteration
keepAminationAlive = false;
}
}
if (keepAminationAlive == true) {
// if the shape should be reredered, the function is called again
setTimeout(animationLoop, 50);
}
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now, for each object in the previous function we need to know which kind of shape to render. This is simply done by checking if the object contains one of the unique shape properties applied to the shape object. Since we are only rendering circles in this demo, this is not a problem. However, if your animation is based on several shapes like on my site (www.engvoldsen.net) - you have to tend to this.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript">// Renders one figure based on the type of figure, testing on figure specific properties.
function renderShapes(tmpShape, id, renderContext) {
if (!isEmpty(tmpShape)) {
// if circle
if (tmpShape.hasOwnProperty("maxRadius")) {
if (tmpShape.runAnimation == true) {
drawCircle(tmpShape, id, renderContext);
}
}
// if line
else if (tmpShape.hasOwnProperty("length")) {
if (tmpShape.runAnimation == true) {
drawLine(tmpShape, renderContext);
}
}
// if box
else if (tmpShape.hasOwnProperty('width')) {
drawBox(tmpShape, renderContext);
} else
return;
}
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Kicking of the animationLoop should give you a decent animation experience ;)
</div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-76589363571232693252015-03-20T10:29:00.004+01:002015-03-20T10:36:52.182+01:00Rendering shapes in Canvas using objects<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
In a previous blog post (Painting using Canvas and JS), I explained how to paint a figure using canvas. I explained how to paint the figure inside a single function by setting coordinates and calling stroke and fill. In the following post, (Create an interactive HTML5 Canvas using event handlers.) I presented the clickable area as an object. In this, post I am going to start up by combining the two like the snippet below.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyJB6gruFrcfP_IPMbVzJv2S60lHWDzgxPyudrI6weaCYr4Z2b7kcXRtSgENgxqC3vvWqoHMpwLUm8a53qsrwh6Pqbpxtj9iLd2uJM77-SSOI-Yuhfvl2uwtLQYEC2m15b3ecCeRM3P1Q/s1600/boxes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyJB6gruFrcfP_IPMbVzJv2S60lHWDzgxPyudrI6weaCYr4Z2b7kcXRtSgENgxqC3vvWqoHMpwLUm8a53qsrwh6Pqbpxtj9iLd2uJM77-SSOI-Yuhfvl2uwtLQYEC2m15b3ecCeRM3P1Q/s1600/boxes.png" /></a></div>
<br />
<br />
I create an object called CustFigure. It has X and Y values and a height and width. This is all we need in order to place it in the grid and to get the size of the figure, say a box.
</div>
<pre class="brush: javascript">
var CustFigure = function (x, y, height, width, label ) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.label = label;
};
function DrawShape(Shape){
var rectWidth = Shape.width;
var rectHeight = Shape.height;
var rectX = Shape.x;
var rectY = Shape.y;
renderContext.beginPath();
renderContext.fillRect(rectX, rectY, rectWidth, rectHeight);
}
// This call is sending the object to the function DrawShape(), rendering the shape.
DrawShape(CustFigure);
</pre>
<div dir="ltr" style="text-align: left;" trbidi="on">
If you want to render many shapes, you can take the following approach. Create an array as a container for all your figures and push each instance of CustFigure in it.
</div>
<pre class="brush: javascript">
var custFigures = [];
var custFigure1 = new CustFigure(10, 10, 75+10, 75+10, " Hello Nerd!");
custFigures.push(custFigure1);
var custFigure2 = new CustFigure(20, 20, 75+20, 75+20, " Hello Nerd!");
custFigures.push(custFigure2);
var custFigure3 = new CustFigure(30, 30, 75+30, 75+30, " Hello Nerd!");
custFigures.push(custFigure3);
</pre>
<div dir="ltr" style="text-align: left;" trbidi="on">
Now, calling the function renderLoop, we render all the shapes in the array.
</div>
<pre class="brush: javascript">
// Loops through the custom shape array calling DrawShape on every shape
function renderLoop() {
var i = custFigures.length;
while (i-- && i >= 0) {
var customShape = custFigures[i];
DrawShape(customShape, i, context);
}
}
</pre>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-72457521394222818322015-01-07T14:03:00.000+01:002015-03-20T10:22:33.866+01:00Create an interactive HTML5 Canvas using event handlers.<div dir="ltr" style="text-align: left;" trbidi="on">
You can use HTML5 Canvas as an alternative approach designing info graphics, branding
graphics etc. Using the example in my previous blog post, I will add a
clickable area on the canvas and use a JavaScript event handler to execute some
logic. <o:p></o:p>
<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This is the result of the previous example. I want to pop an alert Box when clicking inside the logo.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRxFmepfSVBocwybc9KB-96B9T6HmdBO_xvcki5gUBzCSbB1uIa1JNFlLT3Q95GgYTsYi3Rqncryu4cA1-mvTqVjZtWtaQ60lF3eUtUejWExWjahcwUj7cWycniNylLTfREvd_K6LjqXQ/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRxFmepfSVBocwybc9KB-96B9T6HmdBO_xvcki5gUBzCSbB1uIa1JNFlLT3Q95GgYTsYi3Rqncryu4cA1-mvTqVjZtWtaQ60lF3eUtUejWExWjahcwUj7cWycniNylLTfREvd_K6LjqXQ/s1600/2.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: left;">
I need to create an object reflecting the coordinates I want my clickable zone to have. I’m also throwing in an id/name.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript"><span style="background-color: white;"> var CustFigure = function (x, y, height, width, name ) {
this.x = x;
this.y = y;
this.height = height;
this.width = width;
this.name = name;
};
</span></pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In this case I just create a global Array that I can pop the objects on to.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript"> var custFigures = [];
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Calibri;"><span lang="EN-GB" style="mso-ansi-language: EN-GB;">At some
point (I choose to include it in the function drawing</span><span lang="EN-GB" style="mso-ansi-language: EN-GB;"> the logo) we create the object with the
desired coordinates and push it on to the array.<o:p></o:p></span></span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript"> var custFigure = new CustFigure(50, 50, 75+50, 75+50, " Hello Nerd!");
custFigures.push(custFigure);
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now, for the final section; adding the logic to the canvas click event handler.
</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: javascript"> $('#xpCanvasWeb').click(function (e) {
//Picking up the cursor coordinates
var clickedX = e.pageX - this.offsetLeft;
var clickedY = e.pageY - this.offsetTop;
//You might have more than one clickable zone in your canvas.
//We run through the array and compare the coordinates.
for (var i = 0; i < custFigures.length; i++) {
if (clickedX > custFigures[i].x
&& clickedX < custFigures[i].width
&& clickedY > custFigures[i].y
&& clickedY < custFigures[i].height) {
var name = custFigures[i].name;
//When matching we fire of the alert box.
alert("You clicked X=" + clickedX + " and Y=" + clickedY + name);
}
}
});
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The result should look something like the box below.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuYJp0ENM_t3xxtvR-fryKePPUbvK4awm0Wlr_3pXbzAebNZPjiTJTTFSyhn-l23XUxUB91WxngLdQ9qSDbncgYKMNqHtuqDTCJ2pCBYzJlrBOhMiyVWX81xSbZfYZzfBYugFs1m7jwQM/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="1" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuYJp0ENM_t3xxtvR-fryKePPUbvK4awm0Wlr_3pXbzAebNZPjiTJTTFSyhn-l23XUxUB91WxngLdQ9qSDbncgYKMNqHtuqDTCJ2pCBYzJlrBOhMiyVWX81xSbZfYZzfBYugFs1m7jwQM/s1600/1.png" /></a></div>
<br /></div>
<div style="clear: both;">
</div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-31732132935050227852015-01-06T13:44:00.001+01:002015-03-09T13:27:35.068+01:00Painting using Canvas and JS.<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div style="text-align: left;">
<b>Lately I've been playing around with HTML5 and Canvas trying to render icons and graphics without the use of image files. This blog post is simply showing how to render the HTML5 logo using only code.</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0oPGExKFT0ey76XKG3IPS8hJ2Vm1onhYuh2LWsGMDiqucPGyWgePuostRVPOWg1iYSWcPwpFBZmLH8BdSiepRohYjQQyU0jajrfQv1Upp8LjcHCH0yQ7vxJXyCVAccUfPMDkVZ6jugJo/s1600/all.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0oPGExKFT0ey76XKG3IPS8hJ2Vm1onhYuh2LWsGMDiqucPGyWgePuostRVPOWg1iYSWcPwpFBZmLH8BdSiepRohYjQQyU0jajrfQv1Upp8LjcHCH0yQ7vxJXyCVAccUfPMDkVZ6jugJo/s320/all.png" /></a></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
<span lang="EN-GB" style="mso-ansi-language: EN-GB;">First up, we create a HTML5
canvas-tag where our logo will live. I’ll add some simple CSS to it for good measure,
creating a circular form for our logo. </span><span lang="EN-GB" style="mso-ansi-language: EN-GB;"><span style="font-family: Calibri;">We make
sure to call our function rendering the logo as the page is loaded.</span></span></div>
<span lang="EN-GB" style="mso-ansi-language: EN-GB;"><span style="font-family: Calibri;"><o:p></o:p></span></span><br />
<pre class="brush: html"><canvas id="xpCanvasWeb" class="testblock" width="175" height="175"></canvas>
<style type="text/css">
.testblock {
background: none repeat scroll 0 0 #2a2a2e;
border: 1px solid #2a2a2e;
border-radius: 115px;
margin: 10px;
}
</style></pre>
<br />
<br />
<span lang="EN-GB" style="mso-ansi-language: EN-GB;"><span style="font-family: Calibri;">Now, for
the rendering-function, please see my inline code. My approach towards this is
to paint the logo in «layers», starting with the background and adding on layer
by layer until the logo is complete. By using semi-transparent colors, we get
the desired 3D-effect.<o:p></o:p></span></span><br />
<br />
<pre class="brush: javascript">function xpCanvasWeb() {
// We grab the canvas and context.
var c = document.getElementById("xpCanvasWeb");
var ctx = c.getContext("2d");
//Adding color and filling a rect as background
ctx.fillStyle = "#2a2a2e";
ctx.fillRect(0, 0, 175, 175);
// We want to be able to move our logo about without too much fuss, so we declare an x and y variable and add it in the rendering code.
var x = 60;
var y = 50;
//We set the line width to 1 px.
ctx.lineWidth = 1;
//We begin by declaring the start of a path and setting the fill style.
ctx.beginPath();
ctx.fillStyle = "#E34C26";
//Then we move into position and start drawing
//Fig left
ctx.moveTo(x, y);
ctx.lineTo(x + 5, y + 57);
ctx.lineTo(x + 28, y + 63);
ctx.lineTo(x + 51, y + 57);
ctx.lineTo(x + 56, y + 0);
ctx.lineTo(x, y);
ctx.fill();
//Fig center
ctx.beginPath();
ctx.fillStyle = "#F06529";
ctx.moveTo(x + 28, y + 4);
ctx.lineTo(x + 28, y + 58);
ctx.lineTo(x + 47, y + 53);
ctx.lineTo(x + 51, y + 5);
ctx.lineTo(x + 28, y + 5);
ctx.fill();
//Fig right
ctx.beginPath();
ctx.fillStyle = "rgba(255, 255, 255, 0.6)";
ctx.moveTo(x + 46, y + 12);
ctx.lineTo(x + 10, y + 12);
ctx.lineTo(x + 12, y + 33);
ctx.lineTo(x + 35, y + 33);
ctx.lineTo(x + 35, y + 42);
ctx.lineTo(x + 28, y + 45);
ctx.lineTo(x + 21, y + 43);
ctx.lineTo(x + 20, y + 37);
ctx.lineTo(x + 13, y + 37);
ctx.lineTo(x + 13, y + 48);
ctx.lineTo(x + 28, y + 52);
ctx.lineTo(x + 43, y + 48);
ctx.lineTo(x + 45, y + 26);
ctx.lineTo(x + 19, y + 26);
ctx.lineTo(x + 19, y + 20);
ctx.lineTo(x + 45, y + 20);
ctx.lineTo(x + 45, + 12);
ctx.fill();
}
</pre>
</div>
<br />
<br />
The figure shows how the layers build up the logo for each time we call beginPath, add coordinates and call fill again.</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-60698753784115505782014-07-04T13:45:00.000+02:002015-01-06T13:13:56.500+01:00Using parameters in XSLT<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
If you've read some of my previous posts, you've seen examples of using parameters when calling templates.<br />
I earlier wrote about assigning XML structures to variables. Now we are going to use a variable as parameter for a template call.<br />
<br />
Create the variable and send it as a parameter to your template of choice:<br />
<br /></div>
<pre class="brush: html"> <!-- Given a structure like this one... -->
<xsl:variable name="someVariable">
<record>
<artist sex="female">Madonna</artist>
<title>Like a prair</title>
</record>
</xsl:variable>
<xsl:call-template name="targetTemplate">
<xsl:with-param name="string" select="$someVariable" />
<xsl:with-param name="attributeString" select="$someVariable/@sex"/>
</xsl:call-template name="targetTemplate">
</xsl:template>
</pre>
<br />
Grab the variable and do something that makes sense. ;)
<br />
<br />
<pre class="brush: html"> <xsl:template name="targetTemplate">
<xsl:param name="string"/>
<xsl:param name="attributeString"/>
<!-- do something -->
<xsl:if test="contains($attributeString, 'female')">
<xsl:value-of select="$string">
</xsl:if>
</xsl:template>
</pre>
<br />
Note that the variable can change its name, but the name in the "with-param" and "param" tags must match.<br />
<br />
Happy coding! </div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-34114256219626175022014-06-26T09:25:00.001+02:002014-06-26T09:25:23.914+02:00Set the logo of all sites in a SharePoint 2013 site collection using PowerShell - Flash post<div dir="ltr" style="text-align: left;" trbidi="on">
If you want to quickly set the site logo of a complete SharePoint 2013 site collection, enter the following:<br />
<br />
<span style="background-color: white; color: #444444; font-family: 'Courier New'; font-size: 14px; line-height: 24px;">(get-spsite </span><a href="http://sitecollectionurl/" style="background-color: white; border: 0px; color: #9f9f9f; font-family: 'Courier New'; font-size: 14px; line-height: 24px; margin: 0px; outline: none; padding: 0px; vertical-align: baseline;">http://YourSiteCollectionURL</a><span style="background-color: white; color: #444444; font-family: 'Courier New'; font-size: 14px; line-height: 24px;">).AllWebs | foreach {$_.SiteLogoUrl = “/relative/path/to/companylogo.png”; $_.Update()}</span><br />
<span style="background-color: white; color: #444444; font-family: 'Courier New'; font-size: 14px; line-height: 24px;"><br /></span>
<span style="background-color: white; color: #444444; font-family: 'Courier New'; font-size: 14px; line-height: 24px;">Thats all :)</span></div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-8975768240381547662014-06-11T12:48:00.001+02:002014-06-11T12:48:54.420+02:00Open termbased navigation links in new window in SharePoint 2013<div dir="ltr" style="text-align: left;" trbidi="on">
<br />
Term based navigation has been greatly improved in SharePoint 2013, but sometimes you want to open navigation URLs in a new window. However, the term store does not offer such a property so we'll solve it using JavaScript instead.<br />
<br />
In the masterpage <head> element add this script:</head><br />
<br />
<pre>script language="JavaScript"
// Adding an entry to _spBodyOnLoadFunctionNames array so the function runs on pageLoad
_spBodyOnLoadFunctionNames.push("rewriteNavigationLinks");
function rewriteNavigationLinks() {
// collecting anchors
var anchorArray = document.getElementsByTagName("a");
for (var x=0; x<anchorarray .length="" anchorarray="" containing="" filter="" if="" links="" on="" outerhtml.indexof="" targetnewwindow="" x="">0)
{
oldUrl = anchorArray[x].outerHTML;
// adding target attribute
newUrl = oldUrl.replace(/#targetnewwindow/,'" target="_blank');
anchorArray[x].outerHTML = newUrl;
}
}
}
/script
</anchorarray></pre>
<br />
Then in the term store append "#targetnewwindow" on the link to activate the specific link.<br />
<br />
E.g.<br />
<div>
<blockquote class="tr_bq">
<span style="font-size: x-small;"><span style="font-family: Courier New, Courier, monospace;">http://intranet.foo/somepagename.aspx?pid=000#openinnewwindow</span></span><span style="font-size: x-small;"><br /></span></blockquote>
</div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-4220824521063527012014-04-11T09:46:00.004+02:002014-04-11T09:48:39.121+02:00Configuring MySite search center settings for SharePoint 2013 <div dir="ltr" style="text-align: left;" trbidi="on">
<br />
<span lang="EN-US" style="mso-ansi-language: EN-US;">I stumbled over this one
the other day and I (luckily) discovered the solution by accident. <o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0cm 0cm 8pt;">
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;">When
configuring MySite in SharePoint 2013 you are prompted to give up the URL for
your search center. Now, if you’ve set up an Enterprise Search Center as I’ve
done redirecting you to the correct result pages will fail when doing a search
from MySite. Leaving you with an “The page you're looking for doesn't exist”-error.
(Yes, another of MS meaningful errors).</span></span></div>
<div class="MsoNormal" style="margin: 0cm 0cm 8pt;">
<span lang="EN-US" style="mso-ansi-language: EN-US;"></span><span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;">The error
you’ll discover is that you’ve most likely entered something like </span><a href="http://theurlfor/MySearchCenter"><span style="color: #0563c1; font-family: Calibri;">http://theUrlFor/MySearchCenter</span></a><span style="font-family: Calibri;"> on
the MySite configuration, while it should have been </span><a href="http://theurlfor/MySearchCenter/pages"><span style="color: #0563c1; font-family: Calibri;">http://theUrlFor/MySearchCenter/pages</span></a></span></div>
<div class="MsoNormal" style="margin: 0cm 0cm 8pt;">
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;"><strong>Problem:</strong></span></span><span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;"></span></span><br />
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;">When searching
from MySite you get “The page you're looking for doesn't exist”</span></span></div>
<div class="MsoNormal" style="margin: 0cm 0cm 8pt;">
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;"><strong>Reason:</strong></span></span><span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;"></span></span><br />
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;">The search
URL is wrong and SharePoint cannot find the pages that display the search
results.</span></span></div>
<div class="MsoNormal" style="margin: 0cm 0cm 8pt;">
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;"><strong>Solution:</strong></span></span><span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;"></span></span><br />
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="font-family: Calibri;">The
solution giving you least headache is to use the SharePoint PowerShell and
execute the following lines:<o:p></o:p></span></span></div>
<div style="text-align: left;">
</div>
<div class="MsoNormal" style="margin: 0cm 0cm 8pt; text-align: left;">
<span style="background-color: white;"><span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="color: black; font-family: "Courier New", Courier, monospace;">$ssa = Get-SPEnterpriseSearchServiceApplication</span></span><span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="color: black; font-family: "Courier New", Courier, monospace;">$</span></span></span><br />
<span lang="EN-US" style="mso-ansi-language: EN-US;"><span style="background-color: white; color: black; font-family: "Courier New", Courier, monospace;">ssa.SearchCenterUrl = "</span><a href="http://theurlfor/MySearchCenter/pages"><span style="background-color: white; color: black; font-family: "Courier New", Courier, monospace;"></span></a><span style="background-color: white; color: black; font-family: "Courier New", Courier, monospace;"><a href="http://theurlfor/MySearchCenter/pages%22$">http://theUrlFor/MySearchCenter/pages</a></span><a href="https://www.blogger.com/null"></a><a href="https://www.blogger.com/null"><span style="background-color: white; color: black; font-family: "Courier New", Courier, monospace;">"</span></a></span><a href="https://www.blogger.com/null"></a><span style="font-family: "Courier New", Courier, monospace;"><a href="https://www.blogger.com/null"></a><a href="https://www.blogger.com/null"></a><span style="background-color: white; color: black;"><a href="https://www.blogger.com/null">$</a></span></span><br />
<span style="font-family: "Courier New", Courier, monospace;"><span style="color: black;"><span style="background-color: white;">ssa.Update()<o:p></o:p></span></span></span></div>
<span style="background-color: white; color: black;">
</span><br />
<div class="MsoNormal" style="margin: 0cm 0cm 8pt;">
<span style="font-family: Calibri;"><span style="mso-spacerun: yes;"></span><o:p></o:p></span> </div>
Cheers,<br />
Morten</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-57276551582929224802013-09-25T14:35:00.000+02:002013-09-25T22:31:48.899+02:00SharePoint 2013 - Design Manager - Problems connecting to network drive.<div dir="ltr" style="text-align: left;" trbidi="on">
I've been working with SharePoint 2013 lately and I came across a problem trying to upload design files for the design manager.<br />
<br />
This problem occurs when developing directly on Windows Server 2008 R2.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg50o0SY8xwN6F5eNEkbGYOxWjhKOAnzPJBUjU2EsllY1JepcyfWcsluEXbvqo7ICStbTbj1uu42PLgDqemdcIt5WrzsBLpOsgHVXIL8T1WldeHS-iZVuQTa2giWLDvnbZ_wAB-tNuFux0/s1600/spUpload1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg50o0SY8xwN6F5eNEkbGYOxWjhKOAnzPJBUjU2EsllY1JepcyfWcsluEXbvqo7ICStbTbj1uu42PLgDqemdcIt5WrzsBLpOsgHVXIL8T1WldeHS-iZVuQTa2giWLDvnbZ_wAB-tNuFux0/s1600/spUpload1.png" height="233" width="640" /></a></div>
When mapping the provided link to your computer like explained <a href="http://msdn.microsoft.com/en-us/library/jj733519.aspx">here (MSDN)</a>, you get an error "The network name cannot be found."<br />
<br />
As many other problems you'll find when developing on a server this is due to a missing feature. The solution to the problem is enabling <b><i>"Desktop Experience"</i></b> feature.<br />
<br />
Go to the <b>Server Manager</b> and click on <b>"Features"</b> in the left side tree structure. In the main pane click <b>"Add Feature"</b> and check the <b>"Desktop Experience"</b> box. <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI1076yZw-r5d8cHnmhuEeOF_qiAY5yWLS55IwRV5I1s4dOg133DttylyWuFnxxfp3OII-oFVwfuG5Riu9UWw0KqJcLAjrOQ-glZ27vga9GnL7BY6bEwXzz9fQpWJ2f3Y4rGbXNev8j3I/s1600/feat2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI1076yZw-r5d8cHnmhuEeOF_qiAY5yWLS55IwRV5I1s4dOg133DttylyWuFnxxfp3OII-oFVwfuG5Riu9UWw0KqJcLAjrOQ-glZ27vga9GnL7BY6bEwXzz9fQpWJ2f3Y4rGbXNev8j3I/s1600/feat2.png" height="467" width="640" /></a></div>
<br />
<br />
Follow the instructions and make sure to <b>save</b> your work because the Server will have to <b>reboot</b> on finish. <br />
<b></b><br />
When logged in you'll find that mapping the location to your computer will work.</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-42367743642988690242012-09-30T21:43:00.002+02:002012-09-30T21:44:26.573+02:00XPath - the keymaster<p>As you might already know you won't get anywhere without XPath when working with XSLT. As scary as it might sound (at least I thought it sounded scary), it is no more than the pattern you need to learn to find the information you're looking for. Now you might argue that it can be more complicated than that, but we'll keep it simple in this blog post. We'll use the music XML structure from a previous post.</p><p>Let’s see some examples:</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> This code will give you a copy of the XML root of the current structure.</span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">giveMeTheRoot</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:copy-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">//</span>"<span style="color:#0000ff">/></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:template</span>
<span style="color:#0000ff">></span>
</li>
<li> </li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> This template will give you a COPY of the current node. That means that you will also get the subnodes of the current nodes as well.</span>
<span style="color:#0000ff">--></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">giveMeTheCurrentNode</span>"<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:copy-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">.</span>"<span style="color:#0000ff">/></span>
</li>
<li>
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:template</span>
<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3"> </li>
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> This template will give you the VALUE of the current node. This will give you the ONLY the value of the current element, and ignore any subnode value.</span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">giveMeTheCurrentNodeValue</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:value-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">.</span>"<span style="color:#0000ff">/></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:template</span>
<span style="color:#0000ff">></span>
</li>
<li> </li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> For the next example we need to do some changes to the original XML. Let's say we wanted to include the date when the album was released and that we would put this information in an attribute of the record node. That would look something like this.</span>
<span style="color:#0000ff">--></span>
</li>
<li>
<span style="color:#0000ff"><</span>
<span style="color:#a31515">recordCollection</span>
<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff"> </span><span style="color:#ff0000">released</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">01.01.1982</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Madonna<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Like a prair<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff"> </span><span style="color:#ff0000">released</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">01.01.2001</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Gorillaz<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Gorillaz<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3"> ...</li>
<li> ...</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span>
<span style="color:#a31515">recordCollection</span>
<span style="color:#0000ff">></span>
</li>
<li> </li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> This template will return the value of the node attribute called </span>
<span style="color:#0000ff">--></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">giveMeTheCurrentNodesAttribute</span>"<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:value-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">./record/@released</span>"<span style="color:#0000ff">/></span>
</li>
<li>
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:template</span>
<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3"> </li>
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> This example will show how to use XPath to compare values</span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">compareIwithCounter</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:if</span><span style="color:#0000ff"> </span><span style="color:#ff0000">test</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$i </span><span style="color:#ff0000">&gt;</span><span style="color:#0000ff"> $counter</span>"<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:call-template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">test3</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">counter</span>"<span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$counter+1</span>"<span style="color:#0000ff">/></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">i</span>"<span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$i</span>"<span style="color:#0000ff">/></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:call-template</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:if</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:template</span>
<span style="color:#0000ff">></span>
</li>
</ol>
</div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-73908897002948364732012-09-30T21:40:00.001+02:002013-09-19T12:07:06.870+02:00XSLT - Recursion<p>There are a couple of things that make XSLT hard to manage and recursion is indeed one of them. There is just no way of running a traditional for loop. In order to solve this we need either a structure to iterate on, or we can create a template that calls itself with a counter and control number.</p><p>If you simply need to iterate on an XML structure, you can do a for-each loop like this:</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:for-each</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">.//child::title</span>"<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><!--</span><span style="color:#008000"> Do you thing</span><span style="color:#0000ff">--></span>
</li>
<li>
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:for-each</span>
<span style="color:#0000ff">></span>
</li>
</ol>
</div>
</div>
<p>However, if you know that you need to iterate on a procedure "i" times, then we need to complicate things a bit.</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">test3</span>"<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">counter</span>"<span style="color:#0000ff">/></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">i</span>"<span style="color:#0000ff">/></span>
</li>
<li style="background: #f3f3f3"> </li>
<li>
<span style="color:#0000ff"><!--</span><span style="color:#008000">We do our thing...</span><span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:copy</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:text</span><span style="color:#0000ff">></span>Hello Nerd!<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:text</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:copy</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:if</span><span style="color:#0000ff"> </span><span style="color:#ff0000">test</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$i </span><span style="color:#ff0000">&gt;</span><span style="color:#0000ff"> $counter</span>"<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:call-template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">test3</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">counter</span>"<span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$counter+1</span>"<span style="color:#0000ff">/></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">i</span>"<span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$i</span>"<span style="color:#0000ff">/></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:call-template</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:if</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:template</span>
<span style="color:#0000ff">></span>
</li>
</ol>
</div>
</div>
<p>To call the template we need to provide it with the starting parameters:</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:call-template</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">test3</span>"<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">counter</span>"<span style="color:#0000ff">></span>0<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">i</span>"<span style="color:#0000ff">></span>10<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:with-param</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:call-template</span>
<span style="color:#0000ff">></span>
</li>
</ol>
</div>
</div>
<p>Make sure that you take into consideration that the if test checks if the $i is still greater than the $counter variable. If you write greater or equal you will get 10 + 1 runs of the template. Also make sure that the call comes after you've done your magic in the loop. Otherwise you just won't get anything. The template executes line by line, so if you include any code after the template call, it will execute once(!) no matter how many iterations you initially ask for.</p>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0tag:blogger.com,1999:blog-963531920940067565.post-80821751254503194762012-09-23T21:30:00.001+02:002012-09-25T08:27:51.308+02:00Working with XSLT variables<p>Working with variables can get you into any kind of delight or trouble. It brings in many scenarios making it tricky in ways you don't experience with other programming languages.</p><p>
First of all you need to remember that xsl variables are STATIC. That means that you cannot change them once they are set. Also you need to make sure that they are in the correct scope. If you create a variable inside a template, it will only be available inside the template. However, you can create GLOBAL variables outside a template as well.<br /><br />Now on to the code examples. This post is using the XML example from an earlier post on <a href="http://mycodestories.blogspot.no/2012/09/structuring-xml-output.html">XML and XSLT</a>.</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> The following example creates variables in different ways. </span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3"> </li>
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> This variable is a simple string, hardcoded inside the variable node.</span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:variable</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">myString</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:text</span><span style="color:#0000ff">></span>Hello Nerd!<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:text</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:variable</span>
<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> In order to print the variable we do a simple value-of call. </span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:value-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$myString</span>"<span style="color:#0000ff">/></span>
</li>
</ol>
</div>
</div>
<p>This will give us the following output:
<br /><br />
Hello Nerd!
</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> The next variable is created by looking up the artist 'Michael Jackson' in the example XML, and assigning the record title as value to the variable.</span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:variable</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">myArtistAlbum</span>"<span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">//record/title[../artist='Michael Jackson']</span>"<span style="color:#0000ff">/></span>
</li>
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> In order to print the variable we do a simple value-of call. </span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:value-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">$myArtistAlbum</span>"<span style="color:#0000ff">/></span>
</li>
</ol>
</div>
</div>
<p>This will give us the following output:
<br /><br />
Bad
</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> Sometimes we need to load an intire XML structure into a variable. The following exmaple loads a document by using the document() function and the filepath(./music/recordCollection.xml) as an argument. On load we set the xml files root node as the root node in the variable.</span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:variable</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">allArtists</span>"<span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">document('./music/recordCollection.xml')/recordCollection</span>"<span style="color:#0000ff">/></span>
</li>
</ol>
</div>
</div>
<p> When getting the output from this variable, we can do it in two ways.</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> The following code gives us a result similar to the previous example.</span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:value-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">ext:node-set($myArtist)//record/title[../artist='Michael Jackson']</span>"<span style="color:#0000ff">/></span>
</li>
</ol>
</div>
</div>
<p>
This will give us the following output:
<br /><br />
Bad
</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> The following example simply outputs the XML as it is inside the variable. </span>
<span style="color:#0000ff">--></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"><xsl:copy-of select="ext:node-set($finData)"/></span>
<span style="color:#0000ff">--></span>
</li>
</ol>
</div>
</div>
<p>This will give us the following output: </p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><</span>
<span style="color:#a31515">recordCollection</span>
<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Madonna<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Like a prair<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Gorillaz<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Gorillaz<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Madcon<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Beggin<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Michael Jackson<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Bad<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Queen<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Jazz<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Muse<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>The Resistance<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>Duffy<span style="color:#0000ff"></</span><span style="color:#a31515">artist</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Rockferry<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">record</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span>
<span style="color:#a31515">recordCollection</span>
<span style="color:#0000ff">></span>
</li>
<li> </li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> Next up we create a new variable containing an XML structure. We want to create a subset of the original XML containing only titles inside a root node.</span>
<span style="color:#0000ff">--></span>
</li>
<li> </li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:variable</span><span style="color:#0000ff"> </span><span style="color:#ff0000">name</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">titleCollection</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">titleCol</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:for-each</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">.//child::title</span>"<span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:copy-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">.</span>"<span style="color:#0000ff">/></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span><span style="color:#a31515">xsl:for-each</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span><span style="color:#a31515">titleCol</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"></</span>
<span style="color:#a31515">xsl:variable</span>
<span style="color:#0000ff">></span>
</li>
<li> </li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><!--</span>
<span style="color:#008000"> Now when running the copy-of call we get the new XML structure printed out in the result. </span>
<span style="color:#0000ff">--></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">xsl:copy-of</span><span style="color:#0000ff"> </span><span style="color:#ff0000">select</span><span style="color:#0000ff">=</span>"<span style="color:#0000ff">ext:node-set($titleCollection)</span>"<span style="color:#0000ff">/></span>
</li>
</ol>
</div>
</div>
<p>OutPut:</p>
<div class="colorContainer">
<div style="background: #ddd; overflow: auto">
<ol start="1" style="background: #ffffff; margin: 0 0 0 2.5em; padding: 0 0 0 5px;">
<li>
<span style="color:#0000ff"><</span>
<span style="color:#a31515">titleCol</span>
<span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Like a prair<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Gorillaz<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Beggin<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Bad<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Jazz<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>The Resistance<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li style="background: #f3f3f3">
<span style="color:#0000ff"><</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>Rockferry<span style="color:#0000ff"></</span><span style="color:#a31515">title</span><span style="color:#0000ff">></span>
</li>
<li>
<span style="color:#0000ff"></</span>
<span style="color:#a31515">titleCol</span>
<span style="color:#0000ff">></span>
</li>
</ol>
</div>
</div>
Morten Krosby-Sætherhttp://www.blogger.com/profile/04818820423531822741noreply@blogger.com0