├── .babelrc ├── .gitignore ├── .verb.md ├── README.md ├── gulpfile.babel.js ├── package.json ├── src ├── experiments │ └── readme.md ├── faq │ ├── qWidget-widgets │ │ └── readme.md │ └── widget-organization │ │ └── readme.md ├── general │ └── toc │ │ └── readme.md ├── qsio.yml ├── readme.md ├── recipes │ ├── embed-images │ │ └── readme.md │ ├── show-hide │ │ ├── images │ │ │ ├── dialog-insert-properties.png │ │ │ ├── dialog-insert.png │ │ │ └── show-hide-settings.png │ │ └── readme.md │ └── table-with-dynamic-label │ │ ├── images │ │ ├── dynamic-labels-result.png │ │ ├── no-dynamic-label.png │ │ └── prop-custom-labels.png │ │ └── readme.md ├── subjects │ ├── about │ │ └── readme.md │ ├── actions │ │ ├── images │ │ │ └── sample-actions.png │ │ └── readme.md │ ├── concept │ │ └── readme.md │ ├── data-binding-hypercubes │ │ └── readme.md │ ├── debugging │ │ ├── images │ │ │ ├── qw-console-output-settings.png │ │ │ ├── settings-output-pre.png │ │ │ └── settings-output.png │ │ └── readme.md │ ├── faq │ │ └── readme.md │ ├── good-citizen │ │ └── readme.md │ ├── personas │ │ └── readme.md │ ├── responsiveness │ │ ├── images │ │ │ ├── less-300px.png │ │ │ └── more-300px.png │ │ └── readme.md │ ├── styling-widgets-recommendations │ │ └── readme.md │ ├── styling-widgets │ │ └── readme.md │ ├── sys-info │ │ ├── images │ │ │ ├── result_dimensions_measures.png │ │ │ └── result_sheets.png │ │ └── readme.md │ ├── widget-editor │ │ ├── images │ │ │ ├── distraction-free-mode.gif │ │ │ ├── distraction-free-mode.mp4 │ │ │ ├── insert-icons.png │ │ │ ├── insert-properties.png │ │ │ ├── insert-snippets.png │ │ │ ├── resizable-code-areas.gif │ │ │ ├── resizable-code-areas.mp4 │ │ │ └── resize-font.png │ │ └── readme.md │ ├── widget-organization │ │ └── readme.md │ └── widgets-vs-visualization-extensions │ │ └── readme.md └── tutorial │ ├── 00-toc │ └── readme.md │ ├── 01-prerequisites │ ├── downloads │ │ └── widget-exercises.zip │ ├── images │ │ ├── dev-hub.png │ │ └── open-dev-hub.png │ └── readme.md │ ├── 02-basic-concept │ └── readme.md │ ├── actions │ ├── images │ │ ├── example-1.png │ │ └── example-2.png │ └── readme.md │ ├── angularjs-basic │ └── readme.md │ ├── angularjs-binding │ ├── images │ │ ├── create-property.gif │ │ ├── create-property.mp4 │ │ ├── result.gif │ │ └── result.mp4 │ └── readme.md │ ├── containers │ ├── images │ │ └── result.png │ └── readme.md │ ├── css-less │ └── readme.md │ ├── custom-properties │ ├── images │ │ ├── 3-properties.png │ │ ├── 3-result.png │ │ ├── add-reference.gif │ │ ├── add-reference.mp4 │ │ ├── create-header.gif │ │ ├── create-header.mp4 │ │ ├── custom-property-result.gif │ │ ├── custom-property-result.mp4 │ │ ├── dropdown-props.png │ │ ├── dropdown-result.png │ │ ├── new-input-property.gif │ │ ├── new-input-property.mp4 │ │ └── open-property-panel-builder.png │ └── readme.md │ ├── data-binding │ ├── images │ │ └── result.png │ └── readme.md │ ├── kpi-tile-advanced │ ├── images │ │ ├── result.gif │ │ └── result.mp4 │ └── readme.md │ ├── kpi-tile │ ├── images │ │ ├── property-color.png │ │ ├── property-comparison-kpi.png │ │ ├── property-kpi-title.png │ │ ├── property-kpi.png │ │ ├── result.gif │ │ └── result.mp4 │ └── readme.md │ ├── leonardo-ui │ ├── images │ │ └── result.png │ └── readme.md │ └── working-with-data │ └── readme.md └── widget-exercises ├── 0448b7cd-0943-7f5b-9da6-445df9557354.html ├── 0448b7cd-0943-7f5b-9da6-445df9557354.json ├── 04ccf2f4-1e29-6e75-7c92-911ff797d4ce.html ├── 04ccf2f4-1e29-6e75-7c92-911ff797d4ce.json ├── 05e673d3-ea61-4881-b0f3-0247b4070175.html ├── 05e673d3-ea61-4881-b0f3-0247b4070175.json ├── 06df17ea-4470-0eb4-9c2c-26f35961f865.html ├── 06df17ea-4470-0eb4-9c2c-26f35961f865.json ├── 45f9e213-8f63-49d1-a6b4-953d36d08778.html ├── 45f9e213-8f63-49d1-a6b4-953d36d08778.json ├── 4a42fa97-0b4f-bae3-62a6-fabeccc7ac7d.html ├── 4a42fa97-0b4f-bae3-62a6-fabeccc7ac7d.json ├── 8c2394fa-9fb1-468a-8a7b-a458c8784ab5.html ├── 8c2394fa-9fb1-468a-8a7b-a458c8784ab5.json ├── 8f091618-fe18-404a-803c-28ecd1b48465.html ├── 8f091618-fe18-404a-803c-28ecd1b48465.json ├── 93aca595-0ca6-00e2-3097-2b20551ed2c1.html ├── 93aca595-0ca6-00e2-3097-2b20551ed2c1.json ├── a8eedd9a-82a5-7ddd-a6e7-03e2a507d413.html ├── a8eedd9a-82a5-7ddd-a6e7-03e2a507d413.json ├── be80fb2e-4726-4109-9725-c3c00ead636d.html ├── be80fb2e-4726-4109-9725-c3c00ead636d.json ├── c47baad7-5fc8-4d9d-91a0-0e1181355500.html ├── c47baad7-5fc8-4d9d-91a0-0e1181355500.json ├── d68b5361-9a5b-4e17-9a4b-830404206903.html ├── d68b5361-9a5b-4e17-9a4b-830404206903.json ├── ebfefad9-602a-130f-64e7-8a809ec26976.html ├── ebfefad9-602a-130f-64e7-8a809ec26976.json ├── f543f4cc-3b21-b187-4246-ceeb3d3503b3.html ├── f543f4cc-3b21-b187-4246-ceeb3d3503b3.json └── widget-exercises.qext /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/workspace.xml 8 | .idea/tasks.xml 9 | .idea/dictionaries 10 | .idea/vcs.xml 11 | .idea/jsLibraryMappings.xml 12 | 13 | # Sensitive or high-churn files: 14 | .idea/dataSources.ids 15 | .idea/dataSources.xml 16 | .idea/dataSources.local.xml 17 | .idea/sqlDataSources.xml 18 | .idea/dynamic.xml 19 | .idea/uiDesigner.xml 20 | 21 | # Gradle: 22 | .idea/gradle.xml 23 | .idea/libraries 24 | 25 | # Mongo Explorer plugin: 26 | .idea/mongoSettings.xml 27 | 28 | ## File-based project format: 29 | *.iws 30 | 31 | ## Plugin-specific files: 32 | 33 | # IntelliJ 34 | /out/ 35 | 36 | # mpeltonen/sbt-idea plugin 37 | .idea_modules/ 38 | 39 | # JIRA plugin 40 | atlassian-ide-plugin.xml 41 | 42 | # Crashlytics plugin (for Android Studio and IntelliJ) 43 | com_crashlytics_export_strings.xml 44 | crashlytics.properties 45 | crashlytics-build.properties 46 | fabric.properties 47 | ### Node template 48 | # Logs 49 | logs 50 | *.log 51 | npm-debug.log* 52 | 53 | # Runtime data 54 | pids 55 | *.pid 56 | *.seed 57 | 58 | # Directory for instrumented libs generated by jscoverage/JSCover 59 | lib-cov 60 | 61 | # Coverage directory used by tools like istanbul 62 | coverage 63 | 64 | # nyc test coverage 65 | .nyc_output 66 | 67 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 68 | .grunt 69 | 70 | # node-waf configuration 71 | .lock-wscript 72 | 73 | # Compiled binary addons (http://nodejs.org/api/addons.html) 74 | build/Release 75 | 76 | # Dependency directories 77 | node_modules 78 | jspm_packages 79 | 80 | # Optional npm cache directory 81 | .npm 82 | 83 | # Optional REPL history 84 | .node_repl_history -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | # {%= name %} 2 | > {%= description %} 3 | 4 | ## About this Tutorial 5 | 6 | In this tutorial you'll learn how to use, create and maintain widgets in Qlik Sense. 7 | 8 | ### Work in Progress, Always 9 | 10 | This project is work in progress and will and should always remain in this status, that's part of the concept and the idea of creating a living tutorial. 11 | If you want to follow the progress of this project there are some options: 12 | 13 | * [Join GitHub](https://github.com/join) and "watch" or "star" [the project](http://github.com/stefanwalther/widget-tutorial) and you'll get updates 14 | * [Follow me on Twitter](http://twitter.com/waltherstefan), as soon as I have finished a new chapter, I'll announce it there 15 | 16 | ## Chapters 17 | 18 | - [Basic Introduction](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 19 | - [Getting Started](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 20 | - [Components](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 21 | - [Tutorial](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 22 | - [Recipes](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 23 | 24 | 25 | ## Other Tutorials 26 | 27 | - [Qlik Sense visualization extensions tutorial](https://github.com/stefanwalther/qliksense-extension-tutorial) - A comprehensive tutorial how to create Qlik Sense visualization extensions 28 | 29 | ## Author 30 | 31 | **Stefan Walther** 32 | 33 | * [github.com/stefanwalther](https://github.com/stefanwalther) 34 | * [twitter.com/waltherstefan](http://twitter.com/waltherstefan) 35 | * [qliksite.io](http://qliksite.io) 36 | 37 | ## Copyright & License 38 | Copyright © 2016, [Stefan Walther](https://github.com/stefanwalther). 39 | Licensed under the [Creative Commons Attribution 4.0 International (CC-BY-4.0)](https://creativecommons.org/licenses/by/4.0/) Open Source license. 40 | 41 | *** 42 | 43 | {%= include("footer") %} 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # widget-tutorial 2 | > A comprehensive tutorial + recipes to get started with widgets in Qlik Sense. 3 | 4 | ## About this Tutorial 5 | 6 | In this tutorial you'll learn how to use, create and maintain widgets in Qlik Sense. 7 | 8 | ### Work in Progress, Always 9 | 10 | This project is work in progress and will and should always remain in this status, that's part of the concept and the idea of creating a living tutorial. 11 | If you want to follow the progress of this project there are some options: 12 | 13 | * [Join GitHub](https://github.com/join) and "watch" or "star" [the project](http://github.com/stefanwalther/widget-tutorial) and you'll get updates 14 | * [Follow me on Twitter](http://twitter.com/waltherstefan), as soon as I have finished a new chapter, I'll announce it there 15 | 16 | ## Chapters 17 | 18 | - [Basic Introduction](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 19 | - [Getting Started](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 20 | - [Components](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 21 | - [Tutorial](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 22 | - [Recipes](http://qliksite.io/tutorials/qliksense-widgets-tutorial/) 23 | 24 | ## Other Tutorials 25 | 26 | - [Qlik Sense visualization extensions tutorial](https://github.com/stefanwalther/qliksense-extension-tutorial) - A comprehensive tutorial how to create Qlik Sense visualization extensions 27 | 28 | ## Author 29 | 30 | **Stefan Walther** 31 | 32 | * [github.com/stefanwalther](https://github.com/stefanwalther) 33 | * [twitter.com/waltherstefan](http://twitter.com/waltherstefan) 34 | * [qliksite.io](http://qliksite.io) 35 | 36 | ## Copyright & License 37 | Copyright © 2016, [Stefan Walther](https://github.com/stefanwalther). 38 | Licensed under the [Creative Commons Attribution 4.0 International (CC-BY-4.0)](https://creativecommons.org/licenses/by/4.0/) Open Source license. 39 | 40 | *** 41 | 42 | _This file was generated by [verb](https://github.com/verbose/verb), v0.9.0, on June 26, 2016._ 43 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import gulp from 'gulp'; 4 | import zip from 'gulp-zip'; 5 | 6 | 7 | gulp.task('default', () => { 8 | return gulp.src('widget-exercises/*') 9 | .pipe(zip('widget-exercises.zip')) 10 | .pipe(gulp.dest('./src/tutorial/01-prerequisites/downloads')); 11 | }); 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "widget-tutorial", 3 | "version": "0.2.0", 4 | "description": "A comprehensive tutorial + recipes to get started with widgets in Qlik Sense.", 5 | "keywords": [ 6 | "api", 7 | "extensions", 8 | "kpi", 9 | "qap", 10 | "qlik", 11 | "qlik-analytics-platform", 12 | "qlik-sense", 13 | "tables", 14 | "visualizations", 15 | "widgets" 16 | ], 17 | "homepage": "http://qliksite.io/tutorials/qliksense-widget-tutorial/", 18 | "bugs": { 19 | "url": "https://github.com/stefanwalther/widget-tutorial/issues" 20 | }, 21 | "license": "CC-BY-4.0", 22 | "author": "Stefan Walther (https://github.com/stefanwalther)", 23 | "directories": { 24 | "src": "src" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/stefanwalther/widget-tutorial.git" 29 | }, 30 | "scripts": { 31 | "test": "echo \"Error: no test specified\" && exit 1" 32 | }, 33 | "verb": { 34 | "run": true, 35 | "toc": false, 36 | "layout": "nil", 37 | "tasks": [ 38 | "readme" 39 | ] 40 | }, 41 | "devDependencies": { 42 | "babel-core": "^6.9.1", 43 | "babel-preset-es2015": "^6.9.0", 44 | "gulp": "^3.9.1", 45 | "gulp-zip": "^3.2.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/experiments/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Experiments 3 | sub-title: "There is much more as you can (probably) think of ..." 4 | --- 5 | 6 | The current tutorial just covers the very, very basics what you can achieve with the widget concept. 7 | 8 | It is planned to add some nice experiments on top of the basic functionality here. 9 | 10 | So, come back, stay tuned and have a look! 11 | -------------------------------------------------------------------------------- /src/faq/qWidget-widgets/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "qWidget, Widget, etc." 3 | sub-title: "How can qWidget be compared with the Widget concept?" 4 | --- 5 | 6 | {{> toc tocTitle="Overview"}} 7 | 8 | ## How can qWidget and widgets be compared? 9 | qWidget was a prototype developed in the early beginning of Qlik Sense and you will recognise that Widgets for Qlik Sense were developed based on the ideas of qWidget. 10 | Having said that, the biggest different between these solutions (as of Qlik Sense 3.0) are: 11 | 12 | - qWidget is just an experimental prototype (and therefore not supported at all!!!) 13 | - Widgets are fully integrated into Qlik Sense and therefore this concept is also fully supported and it is planned to extend the concept in the future. 14 | - Right now (as of Qlik Sense 3.0 and Widget 1.0) there is especially a gap when it comes to use several components, like 15 | - A date-picker 16 | - A (range-)slider 17 | - Some convenience tools like a debugging-helper 18 | - Inline charts (minicharts) 19 | - etc. 20 | 21 | So Widgets for Qlik Sense are the future, qWidget is (unofficial) legacy. 22 | 23 | ## What's the plan for qWidget 24 | Right now, as there is still a gap between qWidget and Widgets for Qlik Sense, the plan is to make qWidget work with Qlik Sense and as soon as we can offer similar functionality in Widgets for Qlik Sense qWidget will be removed. 25 | 26 | 27 | ## qWidget offers more features ... 28 | Yes, as of Qlik Sense 3.0 there are is some gap between qWidget and widgets in Qlik Sense. As long as as the widget concept will not be in par of the qWidget concept, you can still use qWidgets. 29 | 30 | ## Can I continue to use qWidgets 31 | Yes, certainly you can, but (see above) qWidget is not officially supported and there is no additional development work planned for qWidget. It is planned to make qWidget work with Qlik Sense 3.0, though. 32 | -------------------------------------------------------------------------------- /src/faq/widget-organization/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Widget Organization" 3 | sub-title: "How to organize widgets?" 4 | --- 5 | 6 | ## How to use external chart libraries in widgets? 7 | It's definitely not the idea of widget to use this concept to programmatically create your visualization objects. Widget is a concept focused on declarative languages like Html and CSS. Create a visualization extension if you want to leverage the full power of JavaScript an existing libraries instead. 8 | -------------------------------------------------------------------------------- /src/general/toc/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Widget Tutorial: Table of Contents" 3 | sub-title: "Get started with the widget concept for Qlik Sense" 4 | layout: area-overview 5 | pageOpts: 6 | isDisqus: false 7 | isToc: true 8 | ghOpts: 9 | isEditButton: false 10 | isStarButton: false 11 | --- 12 | -------------------------------------------------------------------------------- /src/qsio.yml: -------------------------------------------------------------------------------- 1 | sections: 2 | - label: "General" 3 | desc: "Unlinked items are in the works and not published, yet. In that case visit the GitHub repository for more details or just help to write on these topcis. Items marked with WIP are already fine to use, but are planned to be improved or extended over time." 4 | pages: 5 | - label: "Table of Contents" 6 | key: "general/toc/" 7 | - label: "Basic Introduction" 8 | desc: "Understand the basic concept of Widgets for Qlik Sense, how it relates to Visualization extensions, and more." 9 | pages: 10 | - label: "The widget concept" 11 | key: "subjects/concept/" 12 | - label: "Widget personas" 13 | key: "subjects/personas/" 14 | - label: "Widgets vs. Visualization extensions" 15 | key: "subjects/widgets-vs-visualization-extensions/" 16 | - label: "Styling widgets" 17 | # key: "subjects/styling-widgets/" 18 | wip: true 19 | - label: "Styling widgets: Recommendations" 20 | key: "subjects/styling-widgets-recommendations/" 21 | - label: "Responsive widgets" 22 | key: "subjects/responsiveness/" 23 | - label: "Actions" 24 | key: "subjects/actions/" 25 | - label: "Debugging widgets" 26 | key: "subjects/debugging/" 27 | - label: "What makes a widget a good citizen?" 28 | key: "subjects/good-citizen/" 29 | - label: "Getting Started" 30 | desc: "Gettings started with using the IDE to create and maintain widgets:" 31 | pages: 32 | - label: "The widget editor" 33 | key: "subjects/widget-editor/" 34 | - label: "Widget organization" 35 | key: "subjects/widget-organization/" 36 | wip: true 37 | - label: "Components" 38 | pages: 39 | - type: item 40 | label: "Component: sys-info" 41 | key: "subjects/sys-info/" 42 | - label: "Tutorial" 43 | pages: 44 | - label: "About the tutorial" 45 | key: "tutorial/00-toc/" 46 | isHidden: true 47 | - label: "Prerequisites" 48 | key: "tutorial/01-prerequisites/" 49 | - label: "The basic concept" 50 | key: "tutorial/02-basic-concept/" 51 | - label: "Basic data-binding" 52 | key: "tutorial/data-binding/" 53 | - label: "Custom properties" 54 | key: "tutorial/custom-properties/" 55 | - label: "Working with data" 56 | key: "tutorial/working-with-data/" 57 | wip: true 58 | - label: "Leonardo UI" 59 | key: "tutorial/leonardo-ui/" 60 | - label: "AngularJS binding" 61 | key: "tutorial/angularjs-binding/" 62 | - label: "Actions" 63 | key: "tutorial/actions/" 64 | wip: true 65 | - label: "Minimalistic KPI tile" 66 | key: "tutorial/kpi-tile/" 67 | - label: "Bonus: Containers" 68 | key: "tutorial/containers/" 69 | - label: "Bonus: Advanced KPI tile" 70 | key: "tutorial/kpi-tile-advanced/" 71 | wip: true 72 | - label: "Recipes" 73 | desc: "Recipes contain solutions to specific problems with some sample source code." 74 | pages: 75 | - label: "Table with dynamic label" 76 | key: "recipes/table-with-dynamic-label/" 77 | - label: "Show/Hide" 78 | key: "recipes/show-hide/" 79 | - label: "FAQ" 80 | pages: 81 | - label: "Widget organization" 82 | key: "faq/widget-organization/" 83 | - label: "What's the difference between qWidget & Widget?" 84 | key: "faq/qWidget-widgets" 85 | - label: "Experiments" 86 | key: "experiments/" 87 | isHidden: true 88 | -------------------------------------------------------------------------------- /src/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Widget Tutorial" 3 | sub-title: "Get started with the widget concept for Qlik Sense" 4 | layout: redirect 5 | redirect: 6 | url: "tutorials/qliksense-widgets-tutorial/general/toc/" 7 | seconds: 0 8 | ghOpts: 9 | isStarButton: false 10 | isEditButton: false 11 | pageOpts: 12 | isToc: false 13 | isDisqus: false 14 | --- 15 | -------------------------------------------------------------------------------- /src/recipes/embed-images/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Embed Images into a Widget" 3 | sub-title: "Step by step guide how to embed images into a widget in Qlik Sense." 4 | draft: true 5 | --- 6 | 7 | https://community.qlik.com/message/1109884#1109884 8 | -------------------------------------------------------------------------------- /src/recipes/show-hide/images/dialog-insert-properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/recipes/show-hide/images/dialog-insert-properties.png -------------------------------------------------------------------------------- /src/recipes/show-hide/images/dialog-insert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/recipes/show-hide/images/dialog-insert.png -------------------------------------------------------------------------------- /src/recipes/show-hide/images/show-hide-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/recipes/show-hide/images/show-hide-settings.png -------------------------------------------------------------------------------- /src/recipes/show-hide/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Show / Hide Elements" 3 | --- 4 | 5 | # Show / Hide 6 | 7 | > Demonstrates how to show / hide parts of your object 8 | 9 | 10 | ## Step by Step 11 | 12 | First create a property using the Property Panel Builder: 13 | 14 | - Drag the "Header" element to the property panel preview 15 | - Expand the "Header" element (by default called "Settings") 16 | - Drag & Drop the "Checkbox" element inside "Settings" 17 | - Make some changes to the newly added "Checkbox" element: 18 | 19 | ![Property settings](images/show-hide-settings.png) 20 | 21 | Then use the following code: 22 | 23 | ```html 24 |
25 | The condition has been evaluated to TRUE 26 |
27 |
28 | The condition has been evaluated to FALSE 29 |
30 | ``` 31 | 32 | Now replace the conditions with a reference to the previously created property. The easiest way to achieve that is to use the "Insert" dialog: 33 | 34 | ![Insert dialog](images/dialog-insert.png) 35 | 36 | Switch to "Property references" and select "Settings" in the Dropdown list: 37 | 38 | ![Insert dialog](images/dialog-insert-properties.png) 39 | 40 | Insert the value inside of `ng-hide` resp. `ng-show`. 41 | 42 | Now your code should be as follows: 43 | 44 | ```html 45 |
46 | The condition has been evaluated to TRUE 47 |
48 |
49 | The condition has been evaluated to FALSE 50 |
51 | ``` 52 | 53 | If you now change the value of the property in the property panel, either the hide or show condition will be evaluated to true. 54 | 55 | ## Reference 56 | 57 | - [AngularJS Documentation for ngShow](https://docs.angularjs.org/api/ng/directive/ngShow) 58 | - [AngularJS Documentation for ngHide](https://docs.angularjs.org/api/ng/directive/ngHide) 59 | -------------------------------------------------------------------------------- /src/recipes/table-with-dynamic-label/images/dynamic-labels-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/recipes/table-with-dynamic-label/images/dynamic-labels-result.png -------------------------------------------------------------------------------- /src/recipes/table-with-dynamic-label/images/no-dynamic-label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/recipes/table-with-dynamic-label/images/no-dynamic-label.png -------------------------------------------------------------------------------- /src/recipes/table-with-dynamic-label/images/prop-custom-labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/recipes/table-with-dynamic-label/images/prop-custom-labels.png -------------------------------------------------------------------------------- /src/recipes/table-with-dynamic-label/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Table with dynamic label" 3 | sub-title: "How to create a table with dynamic labels - defined by the user?" 4 | --- 5 | 6 | [Paul Nowicki](https://community.qlik.com/people/pnowicki) is asking the following question on [Qlik Community](https://community.qlik.com/message/1106071): 7 | 8 | > I'm currently trying to create a widget table where I can have dynamic column labels. This is my attempt at a workaround for Qlik Sense's lack of dynamic labels. Has anyone done this before and can share their widget code? 9 | 10 | ## No magic solution 11 | 12 | When defining dimensions and measures in Widgets you actually run into the same situation as when working with native visualizations: The label cannot be defined by using an express: 13 | 14 | ![](images/no-dynamic-label.png) 15 | 16 | ## A proposed solution 17 | 18 | But due to the flexibility of Widgets there is at least a feasible workaround - even if not 100% user-friendly. 19 | 20 | ### Preparation 21 | 22 | - Create a widget, add the data-section to the property panel and define the desired amount of dimensions and measures. 23 | - Next create a header and an input object, configured as follows: 24 | 25 | ![](images/prop-custom-labels.png) 26 | 27 | - Now let's add the basic code snippet for creating a table and add some dimensions and measures: 28 | 29 | Basic table snippet (from the snippet dialog): 30 | ```html 31 |  32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 |
35 | \{{head.qFallbackTitle}} 36 |
42 | \{{cell.qText}} 43 |
47 |
48 | Please add dimensions and measures. 49 |
50 | ``` 51 | 52 | - In the `customLabels` input field let's define some custom labels, separated with a semi-colon, e.g.: 53 | 54 | ``` 55 | This is header 1;Another header;Third header;Fourth header 56 | ``` 57 | 58 | Now all we have to do is to change the section of the code-snippets where the headings of the table are rendered: 59 | 60 | ```html 61 | ... 62 | 63 | 64 | 65 | \{{settings.customLabels.split(';')[$index]}} 66 | 67 | 68 | 69 | ... 70 | ``` 71 | 72 | So how does this work: 73 | - The content of `settings.customLabels` will first be converted to an array using JavaScript's split method 74 | - Then for each column index, the right one will be taken and rendered 75 | 76 | That's the result: 77 | _(used some stylesheet to make it a bit nicer)_ 78 | 79 | ![](images/dynamic-labels-result.png) 80 | 81 | ## Better solution 82 | 83 | If you have a better solution for this challenge, please do not hesitate to post your findings in the comment section below! 84 | -------------------------------------------------------------------------------- /src/subjects/about/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | sub-title: About this tutorial, how to use, how to contribute ... 4 | --- 5 | 6 | (TBD) 7 | -------------------------------------------------------------------------------- /src/subjects/actions/images/sample-actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/actions/images/sample-actions.png -------------------------------------------------------------------------------- /src/subjects/actions/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Actions 3 | sub-title: "Let your widget interact with Qlik Sense using actions." 4 | --- 5 | 6 | The following actions can be used to make your widget more interactive with Qlik Sense: 7 | 8 | 9 | - `app.clearAll` - Clear all selections. 10 | - `app.back()` – Back to the previous selection 11 | - `app.forward()` – Forward to the next selection 12 | - `navigation.nextSheet()` – Jump to the next sheet 13 | - `navigation.prevSheet()` – Jump to the previous sheet 14 | - `navigation.gotoSheet()` – Jump to a sheet, defined by Id 15 | - `navigation.gotoStory()` – Jump to a story, defined by Id 16 | 17 | *This is just an excerpt of the available actions, for a full list, have a look at the {{#hl}}App API{{/hl}} or the {{#hl}}Navigation API{{/hl}}* 18 | 19 | ## Usage 20 | Bind your widget with an action using e.g. `ng-click` (in case of a button): 21 | 22 | **Html:** 23 | ```html 24 | 25 | 26 | 27 | ``` 28 | 29 | Note: To apply styles, e.g. use the Leonardo-UI styles. 30 | 31 | 32 | ## Example 33 | 34 | This example uses Leonardo-UI styles an some of the predefined actions: 35 | 36 | **Html:** 37 | ```html 38 | 39 | Back 40 | Clear All 41 | Forward 42 | 43 | ``` 44 | 45 | ```css 46 | & { 47 | padding:10px 10px 10px 10px; 48 | 49 | .lui-button { 50 | min-width:100px; 51 | } 52 | } 53 | 54 | ``` 55 | 56 | **Result:** 57 | 58 | ![](images/sample-actions.png) 59 | 60 | 61 | ## FAQ: 62 | 63 | **Q: Is it possible to define custom actions?** 64 | A: Right now, this is not possible, but on the roadmap for future versions. 65 | -------------------------------------------------------------------------------- /src/subjects/concept/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Widget concept" 3 | --- 4 | 5 | The main goal of the Widget concept (introduced in Qlik Sense 3.0) can be described as follows: 6 | 7 | > **Allow users to create new visualizations for Qlik Sense without the need of having any programming skills.** 8 | 9 | Widgets are best suited for creating simple visualizations, such as KPI objects, tables or any other kind of simple information representation. 10 | Widgets can also be used to add simple actions to objects, such as buttons to clear selections, to jump to a different sheet, or to add other visual elements. 11 | 12 | To make it even easier to create widgets, Qlik Sense provides a powerful development environment to create and maintain widgets: **The Widget editor** 13 | -------------------------------------------------------------------------------- /src/subjects/data-binding-hypercubes/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Data binding: Hypercubes" 3 | draft: true 4 | --- 5 | 6 | Dimensions and measures defined in your widget object result in an internal data table, a so-called hypercube, that is being exposed to the object, just like for any other standard Qlik Sense object. This data table can be used in your widget. 7 | 8 | There are some basic objects exposed to the current scope of your widget that you can use. 9 | 10 | Object | Description 11 | ------------------------------------------------| ------------------------------ 12 | `layout.qHyperCube` | Returns the representation of the hypercube, that is, the data table exposed to your widget. 13 | `layout.qHyperCube.qDimensionInfo` | Gets the object array of defined dimensions. 14 | `layout.qHyperCube.qMeasureInfo` | Gets the object array of defined measures. 15 | `layout.qHyperCube.qDataPages[0].qMatrix` | Gets the object array of the data table. 16 | `layout.qHyperCube.qDataPages[0].qMatrix[0]` | Gets the object array of the first row of the data table. 17 | `layout.qHyperCube.qDataPages[0].qMatrix[0][0]` | Gets the object array of the first column in the first row of the data table. 18 | 19 | ### Example: Iterating through dimensions and measures 20 | 21 | ```html 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 34 | 35 | 36 |
{{dim.qFallbackTitle}} 26 | {{mea.qFallbackTitle}} 27 |
32 | {{col.qText}} 33 |
37 | ``` 38 | 39 | 40 | ## Shorthand Notation 41 | Since the above described notation is very powerful, but hard to memorize, there is also a second API available to work with the HyperCube. From within widgets you can also access the [Table API](http://help.qlik.com/en-US/sense-developer/2.2/Subsystems/APIs/Content/TableAPI/qlik-table-interface.htm). 42 | 43 | Object | Description 44 | -------------------------------------- | ------------------------------------------------- 45 | `data.rows` | Get the object array of all rows (including measures and dimensions). 46 | `data.headers` | Get the object array of all headers (including measures and dimensions). 47 | `data.totals` | Get the total information for headers. 48 | `data.rowCount` | Returns the total number of rows of the `qHyperCube`, including rows not fetched from the server. 49 | `data.colCount` | Returns the total number of columns for the `qHyperCube` 50 | 51 | For more information how to use the Table API, please visit the [Table API reference](http://help.qlik.com/en-US/sense-developer/2.2/Subsystems/APIs/Content/TableAPI/QHeader.htm). 52 | 53 | ### Example: Iterating through dimensions and measures using the shorthand notation 54 | 55 | ```html 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
{{head.qFallbackTitle}}
{{cell.qText}}
68 | ``` 69 | -------------------------------------------------------------------------------- /src/subjects/debugging/images/qw-console-output-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/debugging/images/qw-console-output-settings.png -------------------------------------------------------------------------------- /src/subjects/debugging/images/settings-output-pre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/debugging/images/settings-output-pre.png -------------------------------------------------------------------------------- /src/subjects/debugging/images/settings-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/debugging/images/settings-output.png -------------------------------------------------------------------------------- /src/subjects/debugging/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Debugging Widgets 3 | sub-title: Some tips and tricks how to debug Widgets. 4 | draft: false 5 | --- 6 | 7 | When working with data resp. properties in your widgets, it's quite often useful to get the current state of the AngularJS scope, so that you can validate the output or just to get a better understanding of the underlying data-structure. 8 | 9 | ### Just Render it ... 10 | 11 | The easiest way to get some insights of the internal data-structures is to just render it using pure AngularJS functionality and data binding: 12 | 13 | ```html 14 |
15 | ``` 16 | returns the following in the preview area 17 | ![](images/settings-output.png) 18 | 19 | *The AngularJS filter `json` ([> docs](https://docs.angularjs.org/api/ng/filter/json)) actually converts and object to JSON and therefore allows you to see all properties of the given object.* 20 | 21 | This becomes even more useful if you use `pre` for a better readable output: 22 | 23 | ***Html*** 24 | 25 | ```html 26 |
27 | ```
28 | 
29 | 
30 | ***CSS***
31 | 
32 | ```css
33 | .json {
34 | 	font-family: monospace;
35 | }
36 | ```
37 | 
38 | ***Result***
39 | 
40 | ![](images/settings-output-pre.png)
41 |  
42 | 
43 | ### Using Chrome's DevTools & `qw-console`
44 | 
45 | *If you are not familiar with Chrome DevTools or development tools available in nearly every browser, then [the official documentation](https://developer.chrome.com/devtools) is a good starting point. 
46 | But basically just press `F12` and you'll see a developer tool appearing in your browser***
47 | 
48 | There is an experimental component available (as of Qlik Sense 3.0) which allows you to output some information in the developer's console: ``.
49 | 
50 | Just use it anywhere in the Html area as follows:
51 | 
52 | ***Example:***
53 | 
54 | ```html
55 | 
56 | ```
57 | returns then
58 | 
59 | ![](images/qw-console-output-settings.png)
60 | 
61 | ## Usage
62 | 
63 | Log the given object to the console:
64 | 
65 | ```html
66 | 
67 | ```
68 | 
69 | Log the path property of the given data object
70 | 
71 | ```html
72 | 
73 | ```
74 | 
75 | Log the parent scope of the targeted element using a querySelector:
76 | 
77 | ```html
78 | 
79 | 
80 | 
81 | 
82 | 
83 | ```
84 | 


--------------------------------------------------------------------------------
/src/subjects/faq/readme.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: FAQ
 3 | sub-title: "Frequently asked questions"
 4 | ---
 5 | 
 6 | {{> toc}}
 7 | 
 8 | 
 9 | ## How to use external chart libraries in widgets?
10 | It's definitely not the idea of widget to use this concept to programmatically create your visualization objects. Widget is a concept focused on declarative languages like Html and CSS. Create a visualization extension if you want to leverage the full power of JavaScript an existing libraries instead.
11 | 
12 | ## How can qWidget and widgets be compared?
13 | qWidget was a prototype developed in the early beginning of Qlik Sense and you will recognise that Widgets for Qlik Sense were developed based on the ideas of qWidget.
14 | Having said that, the biggest different between these solutions (as of Qlik Sense 3.0) are:
15 | 
16 | - qWidget is just an experimental prototype (and therefore not supported at all!!!)
17 | - Widgets are fully integrated into Qlik Sense and therefore this concept is also fully supported and it is planned to extend the concept in the future.
18 | - Right now (as of Qlik Sense 3.0 and Widget 1.0) there is especially a gap when it comes to use several components, like
19 |     - A date-picker
20 |     - A (range-)slider
21 |     - Some convenience tools like a debugging-helper
22 |     - Inline charts (minicharts)
23 |     - etc.
24 |     
25 | So Widgets for Qlik Sense are the future, qWidget is (unofficial) legacy.
26 | 
27 | ## What's the plan for qWidget
28 | Right now, as there is still a gap between qWidget and Widgets for Qlik Sense, the plan is to make qWidget work with Qlik Sense and as soon as we can offer similar functionality in Widgets for Qlik Sense qWidget will be removed.
29 | 
30 | 
31 | ## qWidget offers more features ...
32 | Yes, as of Qlik Sense 3.0 there are is some gap between qWidget and widgets in Qlik Sense. As long as as the widget concept will not be in par of the qWidget concept, you can still use qWidgets.
33 | 
34 | ## Can I continue to use qWidgets
35 | Yes, certainly you can, but (see above) qWidget is not officially supported and there is no additional development work planned for qWidget. It is planned to make qWidget work with Qlik Sense 3.0, though.
36 | 


--------------------------------------------------------------------------------
/src/subjects/good-citizen/readme.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: What makes a Widget a good citizen
 3 | ---
 4 | 
 5 | A Widget should be:
 6 | 
 7 | - Generic
 8 | - Responsive
 9 | - Declarative Only
10 | 
11 | ## Generic Widgets
12 | 
13 | - Don't hard-code values within widgets, use properties instead and bind to properties as much as you can.
14 | - Test your widgets with different apps, widgets should work independently from the data model.
15 | 
16 | ## Responsive Widgets
17 | 
18 | - Test your widget in the Widget editor for different object sizes.
19 | - Use the resize gripper in the "Preview" pane for testing different object sizes.
20 | 
21 | 
22 | ## Declarative Only
23 | One of the core concepts of widgets is that only Html and CSS/Less should be used.
24 | If you have to use some JavaScript code to create your custom visualization, use the concept of visualization extensions.
25 | 


--------------------------------------------------------------------------------
/src/subjects/personas/readme.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: Widget Personas
 3 | ---
 4 | 
 5 | ## Personas
 6 | 
 7 | The following typical personas are involved in the Widget concept.
 8 | 
 9 | ### Widget creator
10 | 
11 | > The Widget creator creates and maintains widgets.
12 | 
13 | **Required skills:**
14 | - Html
15 | - Css (+ optionally Less)
16 | - Basic concepts of data-binding with AngularJS
17 | 
18 | ### Widget consumer
19 | 
20 | > The Widget consumer uses existing widgets within Qlik Sense - in the same way as any other object type.
21 | 
22 | **Required skills:**
23 | Nothing special, Widgets can be used as any other object type in Qlik Sense.
24 | 
25 | ### Administrator
26 | 
27 | > An Administrator can manage widget libraries by using the QMC.
28 | 
29 | **Required skills:**
30 | Nothing special, widgets are managed in the QMC in exactly the same way as for example visualization extensions.
31 | 


--------------------------------------------------------------------------------
/src/subjects/responsiveness/images/less-300px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/responsiveness/images/less-300px.png


--------------------------------------------------------------------------------
/src/subjects/responsiveness/images/more-300px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/responsiveness/images/more-300px.png


--------------------------------------------------------------------------------
/src/subjects/responsiveness/readme.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | title: "Responsive Widgets"
 3 | sub-title: "How to make your widgets fully responsive."
 4 | ---
 5 | 
 6 | When working with web pages, the most common concept to make web pages responsive is to use [CSS media queries](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries). 
 7 | Media queries can be used to define different styles for different media types/devices based on the width and height of a device, the orientation, etc.
 8 | 
 9 | Media queries is a very useful concept, but in case of widgets (and also visualization extensions) it is not really sufficient respectively does not really help.
10 | 
11 | Let's review why this is the case:
12 | 
13 | - Media-Queries allow you to style parts of your web page depending on the current screen size (also called viewport)
14 | - In case of custom objects for Qlik Sense, we have to apply different styles depending on the object size and is therefore defined by the screen size + the amount of columns and cells an object is spanned over in Qlik Sense' grid system.
15 |  
16 | Therefore an additional concept, called element queries has been provided for styling widgets according to its object size. Widget uses a [CSS element queries polyfil](https://github.com/marcj/css-element-queries) to add support for element based media-queries.
17 | 
18 | ## Usage
19 | 
20 | ***Html:***  
21 | 
22 | ```html
23 | 
24 |
25 | /* Your Content */ 26 |
27 |
28 | ``` 29 | 30 | ***CSS:*** 31 | 32 | ```css 33 | .kpi-widget .inner { 34 | /* default style for the inner element */ 35 | } 36 | 37 | .kpi-widget[max-width~="300px"] .inner { 38 | /* 39 | default style for the inner element 40 | if .kpi-widget has a width of less than 300px 41 | */ 42 | } 43 | ``` 44 | 45 | ## Example 46 | 47 | ***Kpi-Widget with >= 300px*** 48 | ![](images/more-300px.png) 49 | 50 | 51 | ***Widget with less than 300px*** 52 | ![](images/less-300px.png) 53 | 54 | ```html 55 |
56 |
57 | My responsive widget. 58 |
59 |
60 | ``` 61 | 62 | ```css 63 | .kpi-widget .inner { 64 | font-weight:bold; 65 | color:darkgray; 66 | font-size:30px; 67 | } 68 | 69 | .kpi-widget[max-width~="300px"] .inner { 70 | color:red; 71 | font-size:16px; 72 | } 73 | ``` 74 | 75 | 76 | 77 | ## Reference 78 | 79 | The following attributes are supported: 80 | 81 | - `min-width` 82 | - `max-width` 83 | - `min-height` 84 | - `max-height` 85 | -------------------------------------------------------------------------------- /src/subjects/styling-widgets-recommendations/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Styling Widgets - Recommendations" 3 | sub-title: Use Cascading Style Sheets (CSS) to make your widgets just looking great. Go one step further and use the full power of Less to create even more maintainable and re-usable styles. 4 | todos: 5 | - Less explanation 6 | --- 7 | 8 | You can use the full functionality of CSS when styling your widgets. In addition to standard CSS, you can also style your widgets using LESS. 9 | 10 | There are two ways of styling your widgets: 11 | 12 | - Inline styling 13 | - Separated styling 14 | 15 | ## Some Ground Rules & Recommendations 16 | There are only a few rules you should consider when styling your widgets: 17 | 18 | - [Never use Ids](#rule-#1-never-use-ids), always use CSS classes to style your widgets 19 | - [Use separated styles](#recommendation-#1-use-separated-styles) over inline style-attributes as much as you can 20 | - Try to [parametrize your CSS styles](#recommendation-#2-parametrized-css-styles) 21 | 22 | ## Rules & Recommendations 23 | 24 | ### Rule #1: Never use IDs 25 | 26 | **This is bad and not recommended** 27 | 28 | ***Html:*** 29 | ```html 30 |
31 | Your custom content ... 32 |
33 | ``` 34 | 35 | ```css 36 | #my-object { 37 | /* your custom styling */ 38 | } 39 | ``` 40 | 41 | Since the Id attribute of Html objects are supposed to be unique on a single page, this can lead to problems if your widget is used several times on a single sheet. 42 | 43 | Use CSS classes instead: 44 | 45 | **This is OK** 46 | 47 | ```html 48 |
49 | Your custom content ... 50 |
51 | ``` 52 | 53 | ```css 54 | .my-object { 55 | /* your custom styling */ 56 | } 57 | ``` 58 | 59 | ### Recommendation #1: Use Separated Styles 60 | 61 | You can style all your HTML elements using inline style-attributes, but it is recommended to separate your styling code from your HTML code. Separated styling is preferred because: 62 | 63 | - It is easier to maintain 64 | - It is easier to reuse 65 | - It makes it easier for others to understand and read the HTML 66 | 67 | #### Inline Style-Attributes 68 | 69 | Inline styling can be used but is not recommended because of the reduced maintainability and readability of your HTML. 70 | 71 | ***Example: Inline style-attributes*** 72 | 73 | ```html 74 |
75 | This is my Widget 76 |
77 | ``` 78 | 79 | 80 | #### Separated styling 81 | 82 | If you use the separated styling approach, you achieve the same result as in the inline styling example above by declaring the styling in the CSS editor. 83 | 84 | ***Example: Separated styling: HTML*** 85 | 86 | ```html 87 |
88 | This is my Widget 89 |
90 | ``` 91 | 92 | ***Example: Separated styling: CSS*** 93 | 94 | ```css 95 | .myClass { 96 | color:red; 97 | font-weight:bold; 98 | } 99 | ``` 100 | 101 | 102 | ### Recommendation #2: Parametrized CSS Styles 103 | 104 | You can use dynamic data binding inside the CSS/Less definition. 105 | 106 | #### Dynamic CSS properties 107 | 108 | ***CSS/Less:*** 109 | ```css 110 | /* settings.foreColor = #efefef */ 111 | .myClass { 112 | color: {{settings.foreColor}}; 113 | } 114 | ``` 115 | 116 | #### Styling with Less variables 117 | 118 | ***CSS/Less:*** 119 | ```css 120 | /* layout.property1 = #efefef */ 121 | @color: {{settings.foreColor}}; 122 | 123 | .myClass { 124 | color: @color; /* Use the Less variable */ 125 | } 126 | ``` 127 | 128 | ## References & further readings 129 | 130 | - [Less](http://lesscss.org/) 131 | 132 | -------------------------------------------------------------------------------- /src/subjects/styling-widgets/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Styling widgets" 3 | --- 4 | 5 | (TBD) 6 | -------------------------------------------------------------------------------- /src/subjects/sys-info/images/result_dimensions_measures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/sys-info/images/result_dimensions_measures.png -------------------------------------------------------------------------------- /src/subjects/sys-info/images/result_sheets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/sys-info/images/result_sheets.png -------------------------------------------------------------------------------- /src/subjects/sys-info/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The sys-info component 3 | sub-title: "Work with meta-data from Qlik Sense and use them in your widget." 4 | --- 5 | 6 | ## Introduction 7 | 8 | You can retrieve system meta-information to support the development process of widgets or you can add system meta information to custom visualizatons using the qw-sys-info component. The following system metadata information can be retrieved: 9 | 10 | - All apps. 11 | - Sheets and objects in the current app. 12 | - Visualizations in the current app. 13 | - Dimensions and measures in the current app. 14 | - All visualization extensions available. 15 | - All widgets available. 16 | - All bookmarks available. 17 | - All current selections. 18 | - All master objects. 19 | 20 | ## Usage 21 | 22 | **Html:** 23 | ```html 24 | 25 |
    26 |
  • 28 |
29 |
30 | ``` 31 | 32 | **Result:** 33 | (when Helpdesk Management app is selected) 34 | 35 | ![](images/result_sheets.png) 36 | 37 | ## Properties 38 | 39 | The following properties can be used, separated by commas to fetch system information: 40 | 41 | - apps 42 | - sheets 43 | - fields 44 | - measures 45 | - dimensions 46 | - extensions 47 | - bookmarks 48 | - currentselections 49 | - masterobjects 50 | - visualizations 51 | 52 | ## Multiple information 53 | 54 | You can not only fetch one entity but you can combine multiple as shown in the example below: 55 | 56 | ```html 57 | 58 | Dimensions:
59 |
    60 |
  • 61 |
62 | Measures:
63 |
    64 |
  • 65 |
66 |
67 | ``` 68 | 69 | ![](images/result_dimensions_measures.png) 70 | -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/distraction-free-mode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/distraction-free-mode.gif -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/distraction-free-mode.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/distraction-free-mode.mp4 -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/insert-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/insert-icons.png -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/insert-properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/insert-properties.png -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/insert-snippets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/insert-snippets.png -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/resizable-code-areas.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/resizable-code-areas.gif -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/resizable-code-areas.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/resizable-code-areas.mp4 -------------------------------------------------------------------------------- /src/subjects/widget-editor/images/resize-font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/subjects/widget-editor/images/resize-font.png -------------------------------------------------------------------------------- /src/subjects/widget-editor/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: The Widget Editor 3 | sub-title: "Get to know the new Widget editor and how it works." 4 | --- 5 | 6 | ## The Widget Editor 7 | 8 | The Widget editor is the main tool for a [Widget creator](../personas/#widget-creator) to design, create and develop a widget. 9 | 10 | ### Launch the Widget editor 11 | 12 | Access the Widget editor through Dev Hub either by opening an existing Widget library or by just opening the tool. 13 | 14 | ### The structure 15 | 16 | It seems to be unnecessary to describe a UI, but it is on the other hand important to understand some basic concepts of the Widget editor. 17 | 18 | First of all the UI of the Widget editor is separated into different areas: 19 | 20 | 1) Asset panel 21 | 2) Editor 22 | 3) Immediate preview 23 | 4) Property panel / Property panel builder 24 | 25 | ### Insert dialogs 26 | 27 | Use the insert dialog to easily insert 28 | 29 | - Code snippets 30 | - Icons 31 | - Properties 32 | 33 | **Code snippets** 34 | 35 | ![](images/insert-snippets.png) 36 | 37 | **Icons** 38 | 39 | ![](images/insert-icons.png) 40 | 41 | 42 | **Properties** 43 | 44 | ![](images/insert-properties.png) 45 | 46 | 47 | 48 | ### Little convenience helpers 49 | 50 | The Widget editor includes some nice little helpers to make the work with Widget more enjoyable: 51 | 52 | **Adapt coding areas** 53 | 54 | ![](images/resizable-code-areas.gif) 55 | 56 | **Distraction free mode & resizable preview** 57 | 58 | Focus on what you are working on, all-together, only Html, only CSS, etc. 59 | ![](images/distraction-free-mode.gif) 60 | 61 | **Resizable font size** 62 | 63 | Adjust the font size of the code areas. Especially useful if you present Widget on stage or in a presentation. 64 | 65 | ![](images/resize-font.png) 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/subjects/widget-organization/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Widget organization 3 | sub-title: "Widgets can be organized in Widget libraries." 4 | --- 5 | 6 | ## What makes a Widget unique? 7 | When you create a widget in the Widget editor (Dev Hub), a unique Id (Global Unique Identifier) will be created, this makes the widget unique. 8 | This unique Id will be kept, regardless you move or export the widget. The unique Id will also be used to check for duplicates if you import a Widget library. 9 | 10 | **Attention:** 11 | Although widget libraries can be imported either in the QMC or in Dev Hub, the check for the uniqueness of a widget will (as of Qlik Sense 3.0) only be performed in Dev Hub. 12 | It his therefore highly recommended that - if you are not 100% sure that a widget does not exist - you only use the Dev Hub import for widget libraries. 13 | 14 | 15 | ## Organizing widgets in libraries 16 | 17 | {{#hl}}(TBD){{/hl}} 18 | -------------------------------------------------------------------------------- /src/subjects/widgets-vs-visualization-extensions/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Widgets vs. Visualization extensions" 3 | --- 4 | 5 | Widgets and visualization extensions try to achieve the same goal: **_Bring new custom visualizations to Qlik Sense_**. 6 | It is therefore a very legitimate question, when to use which of those two approaches. 7 | 8 | Here are some guidelines: 9 | 10 | **Use the concept of widgets if:** 11 | 12 | - You have no (web-)programming skills and don't want to investigate too much time. 13 | - You have decent Html/CSS skills or you want to invest 1-2 days to learn those fundamental building-blocks of the web. 14 | - You have some Html/CSS code-snippets resulting into a custom visualization and you'd just like to bring those into Qlik Sense. 15 | - You (as a partner) would like to share a library of custom visualizations with your customer. 16 | - You would like to create a set of Corporate Design aligned visualization which can then be used by all Qlik Sense users. 17 | - Time to value is key for you. 18 | 19 | **Use the concept of visualization extensions if:** 20 | 21 | - You have decent skills (web-)programming skills, especially covering JavaScript. 22 | - You need to include an external library (e.g. charting-library) into your custom visualization. 23 | - You need to add (whatever) piece of JavaScript to your custom visualization. 24 | -------------------------------------------------------------------------------- /src/tutorial/00-toc/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Tutorial: Getting Started with Widgets" 3 | --- 4 | 5 | ## About 6 | 7 | If you don't want to read a lot of theory and documentation about the widget concept, then you are at the right place. 8 | Welcome to the widget tutorial, a step by step guide to learn the basic concepts of widgets in Qlik Sense. 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/tutorial/01-prerequisites/downloads/widget-exercises.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/01-prerequisites/downloads/widget-exercises.zip -------------------------------------------------------------------------------- /src/tutorial/01-prerequisites/images/dev-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/01-prerequisites/images/dev-hub.png -------------------------------------------------------------------------------- /src/tutorial/01-prerequisites/images/open-dev-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/01-prerequisites/images/open-dev-hub.png -------------------------------------------------------------------------------- /src/tutorial/01-prerequisites/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prerequisites 3 | sub-title: "What's needed running this tutorial." 4 | --- 5 | 6 | All you need for the following exercises are 7 | 8 | - Qlik Sense Desktop 3.x or 9 | - Qlik Sense Server 3.x 10 | 11 | - [The widget library "widget-exercises"](downloads/widget-exercises.zip) 12 | 13 | In case of Qlik Sense Server open [http[s]://server-name/hub](http[s]://server-name/hub), in case of Qlik Sense Desktop open [http://localhost:4848/hub](http://localhost:4848/hub) 14 | 15 | ## Open Dev Hub 16 | In the hub go to the menu and open Dev Hub: 17 | 18 | ![](images/open-dev-hub.png) 19 | 20 | *Note: In case of Qlik Sense Desktop a new browser window will be opened, minimize the instance of Qlik Sense Desktop while working in the newly opened browser window.* 21 | 22 | In **Dev Hub** you will not only see a new link pointing you to the Widget editor, but also all existing Widget libraries will be shown: 23 | 24 | ![](images/dev-hub.png) 25 | -------------------------------------------------------------------------------- /src/tutorial/02-basic-concept/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Basic Concept" 3 | sub-title: "Make yourself familiar with the basic concepts of the Widget editor." 4 | --- 5 | 6 | ## Exercise 7 | 8 | - Open the Widget library "widget-exercises" 9 | - Create a new widget in the Widget library “widget-exercises” 10 | - Add some “Hello world” in the HTML area and add some formatting in the CSS/Less area 11 | (Always use CSS classes instead of IDs, so `.my-formatting` instead of `#my-object`) 12 | - Save the Widget 13 | - Move your widget to a new library 14 | - Make some modifications (e.g. just add a space) and move the copy back to the library “widget-exercises” 15 | - Use your newly created Widget in an existing app 16 | (do not forget to refresh the browser to get the updated list of Widgets) 17 | - etc. 18 | -------------------------------------------------------------------------------- /src/tutorial/actions/images/example-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/actions/images/example-1.png -------------------------------------------------------------------------------- /src/tutorial/actions/images/example-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/actions/images/example-2.png -------------------------------------------------------------------------------- /src/tutorial/actions/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Actions" 3 | sub-title: "Leverage the power of actions in widgets" 4 | --- 5 | 6 | ## Exercise 7 | 8 | - Start with a new widget (in your existing library) 9 | - Use the insert dialog to insert nicely formatted buttons from the Leonardo UI library 10 | - Add one of the predefined actions by using `ng-click` 11 | - Add some buttons and test the functionality by adding a Widget instance to one of your sheets. 12 | 13 | ## Solution Path 14 | 15 | This shows a sample widget using several actions: 16 | 17 | **Html** 18 | 19 | ```html 20 | 21 | Back 22 | Clear All 23 | Forward 24 | 25 | ``` 26 | 27 | 28 | **CSS** 29 | 30 | ```css 31 | & { 32 | padding:10px 10px 10px 10px; 33 | 34 | .lui-button { 35 | min-width:100px; 36 | } 37 | } 38 | ``` 39 | 40 | **Result** 41 | 42 | ![](images/example-1.png) 43 | 44 | 45 | And another sample widget using actions: 46 | 47 | 48 | **Html** 49 | ```html 50 | Prev Sheet 51 | Next Sheet 52 | ``` 53 | 54 | 55 | **CSS** 56 | ```css 57 | & { 58 | padding:10px 10px 10px 10px; 59 | 60 | .lui-button { 61 | min-width:100px; 62 | } 63 | } 64 | ``` 65 | 66 | **Result** 67 | 68 | ![](images/example-2.png) 69 | 70 | 71 | ## Sample Solution 72 | 73 | By opening the widget "Result: Actions" (widget library "widget-exercises") you can have a look at a proposed solution. 74 | 75 | 76 | ## Bonus Exercise 77 | 78 | - Use the newly created widget in combination with a KPI tile to see changes made in selections. 79 | -------------------------------------------------------------------------------- /src/tutorial/angularjs-basic/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/angularjs-basic/readme.md -------------------------------------------------------------------------------- /src/tutorial/angularjs-binding/images/create-property.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/angularjs-binding/images/create-property.gif -------------------------------------------------------------------------------- /src/tutorial/angularjs-binding/images/create-property.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/angularjs-binding/images/create-property.mp4 -------------------------------------------------------------------------------- /src/tutorial/angularjs-binding/images/result.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/angularjs-binding/images/result.gif -------------------------------------------------------------------------------- /src/tutorial/angularjs-binding/images/result.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/angularjs-binding/images/result.mp4 -------------------------------------------------------------------------------- /src/tutorial/angularjs-binding/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: AngularJS Binding 3 | sub-title: "Use AngularJS to make your widgets more dynamic." 4 | --- 5 | 6 | We have already touched some very basic concepts of AngularJS in previous chapters. 7 | 8 | Now let's work on an example how to bind some logic to a property in the property panel. We want to show some conditional content, depending on whether a checkbox is checked or not. 9 | 10 | Let's start with the exercise "Exercise: AngularJS Binding", then follow these steps: 11 | 12 | - Create a checkbox property, give it a label "Show Details" and a reference named "`showDetails`" 13 | - Create some nicely formatted content which 14 | - is only displayed if `showDetails` is not checked 15 | - is only displayed if `showDetails` is checked 16 | 17 | 18 | ## Solution 19 | 20 | First create the property: 21 | 22 | ![](images/create-property.gif) 23 | 24 | Then let's add some Html code 25 | 26 | ```html 27 |
28 | "Show Details" has been checked ... 29 |
30 |
31 | Nothing to show, please enable "Show Details" ... 32 |
33 | ``` 34 | 35 | ... and the corresponding CSS code 36 | 37 | ```css 38 | .details { 39 | ul { 40 | margin-left:30px; 41 | } 42 | } 43 | .eof { 44 | color: #990000; 45 | font-weight: bold; 46 | } 47 | ``` 48 | 49 | Not really exciting so far, let's add the magic stuff. 50 | We are now using a - so called - AngularJS directive which removes or adds a portion of the HTML shown in the browser depending on a condition - in our case the value of the property `showDetails` (which can either be `true` or `false`). 51 | 52 | ***Modified Html:*** 53 | 54 | ```html 55 | 56 |
57 | ... 58 |
59 | 60 | 61 |
62 | ... 63 |
64 | ``` 65 | 66 | 67 | OK, much better, we have now a working conditional rendering, based on the value of the property `showDetails`: 68 | 69 | ![](images/result.gif) 70 | 71 | 72 | **Finally:** 73 | A proposed solution can be found in the widget "Result: AngularJS Binding" (widget library "widget-exercises"). 74 | 75 | ## References 76 | 77 | - [AngularJS: ngIf](https://docs.angularjs.org/api/ng/directive/ngIf) 78 | - [AngularJS: ngShow](https://docs.angularjs.org/api/ng/directive/ngShow) 79 | - [AngularJS: ngHide](https://docs.angularjs.org/api/ng/directive/ngHide) 80 | -------------------------------------------------------------------------------- /src/tutorial/containers/images/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/containers/images/result.png -------------------------------------------------------------------------------- /src/tutorial/containers/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Bonus: Creating Containers" 3 | --- 4 | 5 | Create a Widget using several containers and a simple navigation between these containers as shown in the solution “Result-Simple-Container”: 6 | 7 | ![](images/result.png) 8 | 9 | ## Solution 10 | 11 | By opening the widget "Result: Simple Container" (widget library "widget-exercises") you can have a look at one proposed solution. 12 | -------------------------------------------------------------------------------- /src/tutorial/css-less/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Using CSS & Less" 3 | sub-title: "Leverage the power of Less & properties to make widgets generic." 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/3-properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/3-properties.png -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/3-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/3-result.png -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/add-reference.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/add-reference.gif -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/add-reference.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/add-reference.mp4 -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/create-header.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/create-header.gif -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/create-header.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/create-header.mp4 -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/custom-property-result.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/custom-property-result.gif -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/custom-property-result.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/custom-property-result.mp4 -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/dropdown-props.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/dropdown-props.png -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/dropdown-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/dropdown-result.png -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/new-input-property.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/new-input-property.gif -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/new-input-property.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/new-input-property.mp4 -------------------------------------------------------------------------------- /src/tutorial/custom-properties/images/open-property-panel-builder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/custom-properties/images/open-property-panel-builder.png -------------------------------------------------------------------------------- /src/tutorial/custom-properties/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Custom properties 3 | --- 4 | 5 | As we now know how to bind properties to the widget output, let's create some custom properties (using the Property Panel builder). 6 | 7 | One of the essential concepts behind widgets is that the widget creator can define how the widget instance can be configured by the end-user. Therefore - as a widget creator - you can define properties, which define the behavior of your widget and which can then be used by the user. 8 | 9 | ## Helper for the following exercises 10 | 11 | As a little helper for the following exercises use the existing widget called "Exercise: Custom Properties" from widget library "widget-exercises". 12 | 13 | This provides some CSS and a little code snippet which makes it easier to output some values: 14 | 15 | ***Html:*** 16 | ```html 17 |
18 | 19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 |
31 | ``` 32 | 33 | ***CSS:*** 34 | ```css 35 | .widget-properties { 36 | 37 | padding: 10px 10px 10px 10px; 38 | 39 | h2 { 40 | font-size:18px; 41 | color: #999; 42 | margin-bottom:20px; 43 | } 44 | 45 | .row { 46 | border-bottom: 1px solid #ccc; 47 | padding-top:2px; 48 | padding-bottom:2px; 49 | } 50 | 51 | .row:after { 52 | content: "."; 53 | display: block; 54 | height: 0; 55 | clear: both; 56 | visibility: hidden; 57 | } 58 | 59 | .row .label { 60 | font-weight: bold; 61 | min-width: 100px; 62 | display:inline-block; 63 | padding-right:20px; 64 | } 65 | 66 | .row .val { 67 | display:inline-block; 68 | } 69 | 70 | .row:nth-child(2n) { 71 | background-color:#F7F7F9; 72 | } 73 | } 74 | ``` 75 | 76 | 77 | 78 | ## Exercise 1: Create a basic input field 79 | 80 | - Create a basic input field using the Property Panel builder 81 | - Render the value of the input field in your widget 82 | 83 | ## Exercise 2: Create a drop-down 84 | 85 | - Create a property using the drop-down type 86 | - Render the selected value in your widget 87 | 88 | ## Exercise 3: Create a drop-down and create a binding in CSS 89 | 90 | - Create another drop-down field 91 | - Add some values, representing the background-color of your widget 92 | - Bind the value not to Html, but use it in your CSS declaration 93 | 94 | --- 95 | 96 | {{#hl}}Don't proceed, first try it, then have a look at the solution ;-){{/hl}} 97 | 98 | 99 | ## Solution exercise #1: Create a basic input field 100 | 101 | Assuming that you are using the existing widget "Exercise: CustomProperties" you can succeed with exercise #1 by following these steps: 102 | 103 | **1) Open the Property Panel builder** 104 | 105 | ![](images/open-property-panel-builder.png) 106 | 107 | **2) Create a new property** 108 | **2a) First create a new header** 109 | Drag and drop the header to the Property Panel. 110 | 111 | ![](images/create-header.gif) 112 | 113 | **2b) Add a new item to the new header** 114 | 115 | ![](images/new-input-property.gif) 116 | 117 | **2c) Finish the editing mode of the Property Panel builder** 118 | 119 | **3) Create a reference to the property in your HTML** 120 | 121 | ![](images/add-reference.gif) 122 | 123 | **4) Test the property** 124 | 125 | Now you can change the value of the property and you'll get an updated widget depending on what you've entered in the property object. 126 | 127 | ![](images/custom-property-result.gif) 128 | 129 | 130 | A proposed solution can be reviewed in the widget "Result: Custom Properties" 131 | 132 | ## Solution exercise #2: Create a drop-down 133 | 134 | A proposed solution can be reviewed in the widget "Result: Custom Properties II": 135 | 136 | ![](images/dropdown-props.png) 137 | 138 | ![](images/dropdown-result.png) 139 | 140 | 141 | ## Solution exercise #3: Create a drop-down and create a binding in CSS 142 | 143 | A proposed solution can be review in the widget "Result: Custom Properties III" (widget library "widget-exercises"): 144 | 145 | ![](images/3-properties.png) 146 | 147 | ![](images/3-result.png) 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /src/tutorial/data-binding/images/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/data-binding/images/result.png -------------------------------------------------------------------------------- /src/tutorial/data-binding/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Basic Data Binding" 3 | sub-title: "Data binding is the essential concept to make your Widgets useful and re-usable." 4 | --- 5 | 6 | ## Exercise 7 | 8 | - Create a new widget, call it “Data-Binding” or use the existing widget “Exercise: DataBinding” from the widget library “widget-exercises”. 9 | - Now let's visualize the default properties which are always available, for every widget: 10 | - Title (`settings.title`) 11 | - Subtitle (`settings.subtitle`) 12 | - Footnote (`settings.footnote`) 13 | - Use the “Insert” dialog to insert references to the properties in your HTML area using the double curly braces syntax, e.g. `\{{settings.title}}` 14 | - Alternatively use AngularJS’ directive `ng-bind` which is a bit harder to read, but from a performance perspective the preferred option. 15 | (there is an example in the widget “Exercise: DataBinding”) 16 | - Save the widget and double-check if rendering works properly in an existing app. 17 | 18 | The final result should render a table with some properties in a format similar like the following one: 19 | 20 | ![](images/result.png) 21 | 22 | {{#hl}}Don't proceed, first try it, then have a look at the solution ;-){{/hl}} 23 | 24 | ## Solution 25 | 26 | By opening the widget "Result: DataBinding" (widget library "widget-exercises") you can have a look at the proposed solution. 27 | 28 | 29 | ## References and further readings 30 | 31 | - [Debugging widgets](../../subjects/debugging) 32 | - [AngularJS ngBind](https://docs.angularjs.org/api/ng/directive/ngBind) 33 | -------------------------------------------------------------------------------- /src/tutorial/kpi-tile-advanced/images/result.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile-advanced/images/result.gif -------------------------------------------------------------------------------- /src/tutorial/kpi-tile-advanced/images/result.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile-advanced/images/result.mp4 -------------------------------------------------------------------------------- /src/tutorial/kpi-tile-advanced/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Create an advanced KPI tile" 3 | sub-title: "The goal is to create an advanced KPI tile using the Widget concept." 4 | --- 5 | 6 | Now we have learned the basics. Let's use all the concepts together to create an advanced KPI tile. 7 | 8 | ## Goal 9 | 10 | The KPI tile should offer the following functionality: 11 | 12 | - The user can add one or more (up to three) measures to be displayed 13 | - In the first view only the most important KPI will be shown, the user has the possibility to show more KPIs on demand 14 | - The user should be able to add an explanatory description 15 | - The user can select the style in the property panel 16 | - The style also includes an icon displayed next to the KPIs 17 | - The user should be able to define a URL, which will represent a web-page, containing more details about the KPIs 18 | - The KPI tile should be fully responsive 19 | 20 | ![](images/result.gif) 21 | 22 | ## Solution 23 | 24 | Have a look into the "Drill KPI", part of the sample widgets, delivered with Qlik Sense. 25 | -------------------------------------------------------------------------------- /src/tutorial/kpi-tile/images/property-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile/images/property-color.png -------------------------------------------------------------------------------- /src/tutorial/kpi-tile/images/property-comparison-kpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile/images/property-comparison-kpi.png -------------------------------------------------------------------------------- /src/tutorial/kpi-tile/images/property-kpi-title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile/images/property-kpi-title.png -------------------------------------------------------------------------------- /src/tutorial/kpi-tile/images/property-kpi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile/images/property-kpi.png -------------------------------------------------------------------------------- /src/tutorial/kpi-tile/images/result.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile/images/result.gif -------------------------------------------------------------------------------- /src/tutorial/kpi-tile/images/result.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/kpi-tile/images/result.mp4 -------------------------------------------------------------------------------- /src/tutorial/kpi-tile/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Simple KPI tile" 3 | sub-title: "The goal is to create a simple KPI tile using the widget concept." 4 | --- 5 | 6 | ## Exercise 7 | 8 | Start by using the existing widget template “Exercise: Minimalistic KPI” in the widget library “widget-exercises”. 9 | - Create a new header in the property panel called “Settings” 10 | - Create the following custom properties using the Property Panel editor 11 | - Title (Input, name “Title”, reference `kpiTitle`) 12 | - KPI (Input, name “KPI”, reference `kpi`) 13 | - Color, containing the values “red”, “green” & “orange” as keys, choose appropriate labels (reference `color`) 14 | - Comparison KPI (Input, reference `comparisionKPI`) 15 | - First extend the existing Widget to make it fully dynamic 16 | - Title, KPI and the color should be bound to the properties defined by the user. 17 | - Test the KPI extensively in an existing app 18 | 19 | {{#hl}}Don't proceed, first try it, then have a look at the solution ;-){{/hl}} 20 | 21 | ## Solution 22 | 23 | First create the properties: 24 | 25 | **`kpiTitle`** 26 | 27 | ![](images/property-kpi-title.png) 28 | 29 | **`kpi`** 30 | 31 | ![](images/property-kpi.png) 32 | 33 | **`color`** 34 | 35 | ![](images/property-color.png) 36 | 37 | **`comparisonKPI`** 38 | 39 | ![](images/property-comparison-kpi.png) 40 | 41 | Now let's add bind the HTML output to some of the properties: 42 | 43 | ```html 44 |
45 |
\{{settings.kpiTitle}}
46 |
\{{settings.kpi}}
47 |
\{{settings.comparisonKPI}}
48 |
49 | ``` 50 | 51 | So far we have bound all properties, except the `color` property. 52 | And here comes a nice trick: 53 | 54 | - If you have a look at the CSS, you'll find some classes there: 55 | - `.bar-green` 56 | - `.bar-orange` 57 | - `.bar-red` 58 | - Now let's bind to these classes, depending on the selected color: 59 | 60 | ```html 61 | ... 62 |
\{{settings.comparisonKPI}}
63 | ... 64 | ``` 65 | 66 | ## The Final Result 67 | 68 | ![](images/result.gif) 69 | A proposed solution can be review in the widget "Result: Minimalistic KPI" (widget library "widget-exercises"). 70 | -------------------------------------------------------------------------------- /src/tutorial/leonardo-ui/images/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanwalther/widget-tutorial/03594ea3491842c1dfbce208beaaadc2d9d42916/src/tutorial/leonardo-ui/images/result.png -------------------------------------------------------------------------------- /src/tutorial/leonardo-ui/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Using Leonardo-UI" 3 | sub-title: "Bring the typical Look & Feel of Qlik Sense into your widgets." 4 | --- 5 | 6 | ## Exercise 7 | 8 | - Create a new widget and call it “Leonardo-UI” 9 | - Use the “Insert” dialog to add code snippets using Leonardo-UI 10 | 11 | ## Bonus exercise 12 | 13 | - Make e.g. a ButtonGroup dynamic by combining Leonardo-UI and AngularJS 14 | 15 | ## Solution 16 | 17 | This is how your widget could look like: 18 | 19 | ![](images/result.png) 20 | 21 | A possible result can be seen in “Result: Leonardo-UI” as part of the widget library “widget-exercises”. 22 | 23 | -------------------------------------------------------------------------------- /src/tutorial/working-with-data/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Working with Data" 3 | sub-title: "Create a widget and render a hyperCube with custom formatting" 4 | --- 5 | 6 | ## Exercise 7 | 8 | - Open the widget „Exercise: FormattedTable“ from the widget library „widget-exercises“. 9 | - Create a data section using the Property Panel editor. Choose some meaningful settings for the data section. 10 | - Iterate through dimensions and measures to render the output (use e.g. the code snippet "Table created based on dimensions and measures" ) 11 | 12 | ## Bonus Exercise 13 | 14 | - Create buttons (e.g by using Leonardo-UI) in every row, linking dynamically to an external website. 15 | 16 | -------------------------------------------------------------------------------- /widget-exercises/0448b7cd-0943-7f5b-9da6-445df9557354.html: -------------------------------------------------------------------------------- 1 | 47 |
-------------------------------------------------------------------------------- /widget-exercises/0448b7cd-0943-7f5b-9da6-445df9557354.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Exercise: Formatted Table", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "table" 8 | }, 9 | "properties": {} 10 | } -------------------------------------------------------------------------------- /widget-exercises/04ccf2f4-1e29-6e75-7c92-911ff797d4ce.html: -------------------------------------------------------------------------------- 1 | 15 |
16 |
17 | Hello, this is my widget: 18 |
19 |
20 | This is the title: {{settings.title}} 21 |
22 |
23 |
-------------------------------------------------------------------------------- /widget-exercises/04ccf2f4-1e29-6e75-7c92-911ff797d4ce.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Basic Concept", 3 | "description": "Just a very, very basic widget.", 4 | "author": "Stefan Walther", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [], 11 | "settings": [] 12 | } 13 | } -------------------------------------------------------------------------------- /widget-exercises/05e673d3-ea61-4881-b0f3-0247b4070175.html: -------------------------------------------------------------------------------- 1 | 38 |
39 |
{{settings.kpiTitle}}
40 |
{{settings.kpi}}
41 |
{{settings.comparisonKPI}}
42 |
43 |
-------------------------------------------------------------------------------- /widget-exercises/05e673d3-ea61-4881-b0f3-0247b4070175.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Minimalistic KPI", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "kpi" 8 | }, 9 | "properties": { 10 | "sections": [ 11 | { 12 | "type": "header", 13 | "order": 0, 14 | "parent": "qw-pe-dropzone0-0", 15 | "ref": "header1", 16 | "label": "Settings" 17 | } 18 | ], 19 | "settings": [ 20 | { 21 | "type": "string", 22 | "expression": "optional", 23 | "defaultValue": "", 24 | "order": 0, 25 | "parent": "header1", 26 | "ref": "kpiTitle", 27 | "label": "Title" 28 | }, 29 | { 30 | "type": "string", 31 | "expression": "optional", 32 | "defaultValue": "", 33 | "order": 1, 34 | "parent": "header1", 35 | "ref": "kpi", 36 | "label": "KPI" 37 | }, 38 | { 39 | "component": "dropdown", 40 | "type": "string", 41 | "defaultValue": "red", 42 | "options": [ 43 | { 44 | "label": "Red", 45 | "value": "red" 46 | }, 47 | { 48 | "label": "Orange", 49 | "value": "orange" 50 | }, 51 | { 52 | "label": "Green", 53 | "value": "green" 54 | } 55 | ], 56 | "order": 2, 57 | "parent": "header1", 58 | "ref": "color", 59 | "label": "Color" 60 | }, 61 | { 62 | "type": "string", 63 | "expression": "optional", 64 | "defaultValue": "", 65 | "order": 3, 66 | "parent": "header1", 67 | "ref": "comparisonKPI", 68 | "label": "Comparison KPI" 69 | } 70 | ] 71 | } 72 | } -------------------------------------------------------------------------------- /widget-exercises/06df17ea-4470-0eb4-9c2c-26f35961f865.html: -------------------------------------------------------------------------------- 1 | 38 |
39 |
40 |
41 |
42 |
43 |
-------------------------------------------------------------------------------- /widget-exercises/06df17ea-4470-0eb4-9c2c-26f35961f865.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Exercise: Minimalistic KPI", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "kpi" 8 | }, 9 | "properties": { 10 | "sections": [], 11 | "settings": [] 12 | } 13 | } -------------------------------------------------------------------------------- /widget-exercises/45f9e213-8f63-49d1-a6b4-953d36d08778.html: -------------------------------------------------------------------------------- 1 | 43 |
44 | 45 |
46 |
47 | My Custom Property 48 |
49 |
50 | {{settings.customProperty}} 51 |
52 |
53 | 54 |
55 |
56 | Dropdown Value 57 |
58 |
59 | {{settings.fooBarBaz}} 60 |
61 |
62 | 63 | 64 |
-------------------------------------------------------------------------------- /widget-exercises/45f9e213-8f63-49d1-a6b4-953d36d08778.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Custom Property III", 3 | "description": "", 4 | "author": "Stefan Walther", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [ 11 | { 12 | "type": "header", 13 | "order": 0, 14 | "parent": "qw-pe-dropzone0-0", 15 | "ref": "header1", 16 | "label": "Settings" 17 | } 18 | ], 19 | "settings": [ 20 | { 21 | "type": "string", 22 | "expression": "optional", 23 | "defaultValue": "", 24 | "order": 0, 25 | "parent": "header1", 26 | "ref": "customProperty", 27 | "label": "Custom Property" 28 | }, 29 | { 30 | "component": "dropdown", 31 | "type": "string", 32 | "defaultValue": "foo", 33 | "options": [ 34 | { 35 | "label": "foo", 36 | "value": "foo" 37 | }, 38 | { 39 | "label": "bar", 40 | "value": "bar" 41 | }, 42 | { 43 | "label": "baz", 44 | "value": "baz" 45 | } 46 | ], 47 | "order": 1, 48 | "parent": "header1", 49 | "ref": "fooBarBaz", 50 | "label": "My Dropdown" 51 | }, 52 | { 53 | "component": "dropdown", 54 | "type": "string", 55 | "defaultValue": "#efefef", 56 | "options": [ 57 | { 58 | "label": "Light Gray", 59 | "value": "#efefef" 60 | }, 61 | { 62 | "label": "Dark Gray", 63 | "value": "#333" 64 | }, 65 | { 66 | "label": "Dark Red", 67 | "value": "#990000" 68 | } 69 | ], 70 | "order": 2, 71 | "parent": "header1", 72 | "ref": "backgroundColor", 73 | "label": "Background color" 74 | } 75 | ] 76 | } 77 | } -------------------------------------------------------------------------------- /widget-exercises/4a42fa97-0b4f-bae3-62a6-fabeccc7ac7d.html: -------------------------------------------------------------------------------- 1 | 41 |
42 |

Some properties of this Widget

43 |
44 |
settings.title
45 | 46 |
47 |
48 |
49 |
settings.subtitle
50 | 51 |
52 |
53 |
54 |
settings.footnote
55 | 56 |
57 |
58 |
59 |
-------------------------------------------------------------------------------- /widget-exercises/4a42fa97-0b4f-bae3-62a6-fabeccc7ac7d.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Exercise: DataBinding", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [], 11 | "settings": [] 12 | } 13 | } -------------------------------------------------------------------------------- /widget-exercises/8c2394fa-9fb1-468a-8a7b-a458c8784ab5.html: -------------------------------------------------------------------------------- 1 | 40 |
41 | 42 |
43 |
44 | My Custom Property 45 |
46 |
47 | {{settings.customProperty}} 48 |
49 |
50 | 51 |
52 |
53 | Dropdown Value 54 |
55 |
56 | {{settings.fooBarBaz}} 57 |
58 |
59 | 60 | 61 |
-------------------------------------------------------------------------------- /widget-exercises/8c2394fa-9fb1-468a-8a7b-a458c8784ab5.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Custom Property II", 3 | "description": "", 4 | "author": "Stefan Walther", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [ 11 | { 12 | "type": "header", 13 | "order": 0, 14 | "parent": "qw-pe-dropzone0-0", 15 | "ref": "header1", 16 | "label": "Settings" 17 | } 18 | ], 19 | "settings": [ 20 | { 21 | "type": "string", 22 | "expression": "optional", 23 | "defaultValue": "", 24 | "order": 0, 25 | "parent": "header1", 26 | "ref": "customProperty", 27 | "label": "Custom Property" 28 | }, 29 | { 30 | "component": "dropdown", 31 | "type": "string", 32 | "defaultValue": "foo", 33 | "options": [ 34 | { 35 | "label": "foo", 36 | "value": "foo" 37 | }, 38 | { 39 | "label": "bar", 40 | "value": "bar" 41 | }, 42 | { 43 | "label": "baz", 44 | "value": "baz" 45 | } 46 | ], 47 | "order": 1, 48 | "parent": "header1", 49 | "ref": "fooBarBaz", 50 | "label": "My Dropdown" 51 | } 52 | ] 53 | } 54 | } -------------------------------------------------------------------------------- /widget-exercises/8f091618-fe18-404a-803c-28ecd1b48465.html: -------------------------------------------------------------------------------- 1 | 2 |

Single Buttons:

3 | 4 | Default 5 | 6 | Success 7 | 8 | Warning 9 | 10 | Error 11 |
12 | 13 |

Button Group

14 | 15 |
16 | 19 | 22 | 25 |
26 | 27 |
28 |

Input

29 | 30 | 31 |
32 |

Input Group

33 |
34 | 37 | 38 | 41 |
42 | 43 |
44 |

Checkbox

45 | 52 | 53 |
54 |

Radio Button

55 | 62 | 69 | 70 |
71 |

Select

72 | 73 | 74 | 75 | 76 | 77 | 78 |
79 |

Switch

80 |
81 | 88 |
-------------------------------------------------------------------------------- /widget-exercises/8f091618-fe18-404a-803c-28ecd1b48465.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Leonardo UI", 3 | "description": "An overview of how to use the Leonardo UI components.", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": {} 10 | } -------------------------------------------------------------------------------- /widget-exercises/93aca595-0ca6-00e2-3097-2b20551ed2c1.html: -------------------------------------------------------------------------------- 1 | 16 |

ng-if

17 | 18 |
19 | Here are the details, actually it could be any content: 20 | 21 |
    22 |
  • A table
  • 23 |
  • A qlik-visual
  • 24 |
  • Some KPIs
  • 25 |
26 | The imagination is the only limitation ... 27 |
28 |
29 | Nothing to show, please enable "Show Details" ... 30 |
31 | 32 |
33 | 34 |
-------------------------------------------------------------------------------- /widget-exercises/93aca595-0ca6-00e2-3097-2b20551ed2c1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: AngularJS Binding", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [ 11 | { 12 | "type": "header", 13 | "order": 1, 14 | "parent": "qw-pe-dropzone0-1", 15 | "ref": "header1", 16 | "label": "Settings" 17 | } 18 | ], 19 | "settings": [ 20 | { 21 | "type": "boolean", 22 | "expression": "optional", 23 | "defaultValue": true, 24 | "order": 0, 25 | "parent": "header1", 26 | "ref": "showDetails", 27 | "label": "Show Details" 28 | } 29 | ] 30 | } 31 | } -------------------------------------------------------------------------------- /widget-exercises/a8eedd9a-82a5-7ddd-a6e7-03e2a507d413.html: -------------------------------------------------------------------------------- 1 | 24 |
25 |
    26 |
  • Container 1
  • 27 |
  • Container 2
  • 28 |
  • Container 3
  • 29 |
30 |
31 |
32 | You have selected 33 |
34 | Container 1 35 |
36 |
37 | Container 2 38 |
39 |
40 | Container 3 41 |
42 |
-------------------------------------------------------------------------------- /widget-exercises/a8eedd9a-82a5-7ddd-a6e7-03e2a507d413.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Simple Container", 3 | "description": "", 4 | "author": "Stefan Walther", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": {} 10 | } 11 | -------------------------------------------------------------------------------- /widget-exercises/be80fb2e-4726-4109-9725-c3c00ead636d.html: -------------------------------------------------------------------------------- 1 | 40 |
41 | 42 | 43 |
44 |
45 | My Custom Property 46 |
47 |
48 | {{settings.customProperty}} 49 |
50 |
51 | 52 | 53 |
-------------------------------------------------------------------------------- /widget-exercises/be80fb2e-4726-4109-9725-c3c00ead636d.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Custom Property", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [ 11 | { 12 | "type": "header", 13 | "order": 0, 14 | "parent": "qw-pe-dropzone0-0", 15 | "ref": "header1", 16 | "label": "Settings" 17 | } 18 | ], 19 | "settings": [ 20 | { 21 | "type": "string", 22 | "expression": "optional", 23 | "defaultValue": "", 24 | "order": 0, 25 | "parent": "header1", 26 | "ref": "customProperty", 27 | "label": "Custom Property" 28 | } 29 | ] 30 | } 31 | } -------------------------------------------------------------------------------- /widget-exercises/c47baad7-5fc8-4d9d-91a0-0e1181355500.html: -------------------------------------------------------------------------------- 1 | 41 |
42 |

Some properties of this Widget

43 |
44 |
settings.title
45 | 46 |
{{settings.title}}
47 |
48 |
49 |
settings.subtitle
50 | 51 |
{{settings.subtitle}}
52 |
53 |
54 |
settings.footnote
55 | 56 |
57 |
58 |
59 |
-------------------------------------------------------------------------------- /widget-exercises/c47baad7-5fc8-4d9d-91a0-0e1181355500.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: DataBinding", 3 | "description": "Possible result of exercise on data-binding", 4 | "author": "Stefan Walther", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [], 11 | "settings": [] 12 | } 13 | } -------------------------------------------------------------------------------- /widget-exercises/d68b5361-9a5b-4e17-9a4b-830404206903.html: -------------------------------------------------------------------------------- 1 | 40 |
41 | 42 | 43 |
44 |
45 | 46 |
47 |
48 | 49 |
50 |
51 | 52 | 53 |
-------------------------------------------------------------------------------- /widget-exercises/d68b5361-9a5b-4e17-9a4b-830404206903.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Exercise: Custom Properties", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": { 10 | "sections": [], 11 | "settings": [] 12 | } 13 | } -------------------------------------------------------------------------------- /widget-exercises/ebfefad9-602a-130f-64e7-8a809ec26976.html: -------------------------------------------------------------------------------- 1 | 17 |

Use ng-if

18 | 19 | 20 |
    21 |
  • Create a new property called "Show Details" of type checkbox and reference-name showDetails, by default it should NOT be checked.
  • 22 |
  • Create a div below (with some meaningful content) which should only be shown if showDetails is checked
  • 23 |
  • Create a div below (with some meaningful content) which should only be shown if showDetails is NOT checked
  • 24 |
25 | 26 |
-------------------------------------------------------------------------------- /widget-exercises/ebfefad9-602a-130f-64e7-8a809ec26976.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Exercise: AngularJS Binding", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "other" 8 | }, 9 | "properties": {} 10 | } -------------------------------------------------------------------------------- /widget-exercises/f543f4cc-3b21-b187-4246-ceeb3d3503b3.html: -------------------------------------------------------------------------------- 1 | 10 |
11 | Back 12 | Clear All 13 | Forward 14 | 15 |
16 | 17 | Prev Sheet 18 | Next Sheet 19 |
-------------------------------------------------------------------------------- /widget-exercises/f543f4cc-3b21-b187-4246-ceeb3d3503b3.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Result: Actions", 3 | "description": "", 4 | "author": "", 5 | "library": "widget-exercises", 6 | "meta": { 7 | "type": "button" 8 | }, 9 | "properties": {} 10 | } -------------------------------------------------------------------------------- /widget-exercises/widget-exercises.qext: -------------------------------------------------------------------------------- 1 | { 2 | "name": "widget-exercises", 3 | "description": "Widget Exercises", 4 | "type": "widget-library", 5 | "version": 1, 6 | "author": "Stefan Walther", 7 | "widgets": [ 8 | "04ccf2f4-1e29-6e75-7c92-911ff797d4ce", 9 | "c47baad7-5fc8-4d9d-91a0-0e1181355500", 10 | "4a42fa97-0b4f-bae3-62a6-fabeccc7ac7d", 11 | "d68b5361-9a5b-4e17-9a4b-830404206903", 12 | "be80fb2e-4726-4109-9725-c3c00ead636d", 13 | "8c2394fa-9fb1-468a-8a7b-a458c8784ab5", 14 | "45f9e213-8f63-49d1-a6b4-953d36d08778", 15 | "0448b7cd-0943-7f5b-9da6-445df9557354", 16 | "8f091618-fe18-404a-803c-28ecd1b48465", 17 | "ebfefad9-602a-130f-64e7-8a809ec26976", 18 | "93aca595-0ca6-00e2-3097-2b20551ed2c1", 19 | "a8eedd9a-82a5-7ddd-a6e7-03e2a507d413", 20 | "f543f4cc-3b21-b187-4246-ceeb3d3503b3", 21 | "06df17ea-4470-0eb4-9c2c-26f35961f865", 22 | "05e673d3-ea61-4881-b0f3-0247b4070175" 23 | ] 24 | } 25 | --------------------------------------------------------------------------------