<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Qlik Sense Mashup - Qlik Sense - Обучение, учебник, онлайн курс</title>
	<atom:link href="https://qliksense.ivan-shamaev.ru/tag/qlik-sense-mashup/feed/" rel="self" type="application/rss+xml" />
	<link>https://qliksense.ivan-shamaev.ru/tag/qlik-sense-mashup/</link>
	<description>Qlik Sense на русском языке. Пошаговые уроки для изучения Клик Сенс</description>
	<lastBuildDate>Wed, 02 Dec 2020 20:04:56 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.1</generator>

<image>
	<url>https://qliksense.ivan-shamaev.ru/wp-content/uploads/2018/07/QlikSense_ICON2-150x150.png</url>
	<title>Qlik Sense Mashup - Qlik Sense - Обучение, учебник, онлайн курс</title>
	<link>https://qliksense.ivan-shamaev.ru/tag/qlik-sense-mashup/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>nebula.js &#8211; Qlik Sense API Javascript библиотека. Примеры</title>
		<link>https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/</link>
					<comments>https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/#respond</comments>
		
		<dc:creator><![CDATA[qliksense-expert]]></dc:creator>
		<pubDate>Wed, 25 Nov 2020 20:03:24 +0000</pubDate>
				<category><![CDATA[Уровень 2]]></category>
		<category><![CDATA[mashup]]></category>
		<category><![CDATA[nebula.js]]></category>
		<category><![CDATA[qlik api]]></category>
		<category><![CDATA[qlik sense]]></category>
		<category><![CDATA[qlik sense api]]></category>
		<category><![CDATA[Qlik Sense Mashup]]></category>
		<category><![CDATA[qliksense]]></category>
		<guid isPermaLink="false">https://qliksense.ivan-shamaev.ru/?p=2440</guid>

					<description><![CDATA[<p>Введение в nebula.js nebula.js представляет собой набор библиотек JavaScript, визуализаций и интерфейсов командной строки, которые помогают разработчикам создавать и интегрировать визуализации поверх ассоциативного движка Qlik. Коллекция организована в @nebula.jsрамках области в виде пакетов npm. Основной пакет @nebula.js/stardustсодержит API-интерфейсы для интеграции существующих визуализаций с гибридными приложениями, а также API-интерфейсы для создания пользовательских визуализаций. EMBEDDING VISUALIZATIONS.<a class="moretag" href="https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/"> Читать дальше&#8230;</a></p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/">nebula.js &#8211; Qlik Sense API Javascript библиотека. Примеры</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h1 id="introduction-to-nebulajs"><span>Введение в nebula.js</span></h1>
<p><code class="language-text">nebula.js</code><span> представляет собой набор библиотек JavaScript, визуализаций и интерфейсов командной строки, которые помогают разработчикам создавать и интегрировать визуализации поверх ассоциативного движка Qlik.</span></p>
<p><span>Коллекция организована в </span><code class="language-text">@nebula.js</code><span>рамках области в виде пакетов npm. Основной пакет </span><code class="language-text">@nebula.js/stardust</code><span>содержит API-интерфейсы для интеграции существующих визуализаций с гибридными приложениями, а также API-интерфейсы для создания пользовательских визуализаций.</span></p>
<h1><strong>EMBEDDING VISUALIZATIONS. ВСТРАИВАНИЕ ВИЗУАЛИЗАЦИЙ</strong></h1>
<h2>Configuration. Конфигурация</h2>
<p><span>Когда вы создаете веб-сайт, будь то сайт всей компании или небольшой личный проект, у вас, скорее всего, есть свои собственные рекомендации по дизайну, шаблоны и требования UX, и вы захотите применить эти рекомендации к тому, что вы с ним интегрируете; диаграммы должны использовать ваши цветовые схемы, шрифты, языковой стандарт и уважать любые ограничения, которые могут быть у вас на интерактивность. Вы также можете контролировать, как загружаются диаграммы и темы, в зависимости от того, подключено ли ваше решение к сети или нет.</span></p>
<p><span>Вы можете управлять большинством из них через </span><code class="language-text">Configuration</code><span>объект.</span></p>
<h3 id="temporary-config">В<span>ременный конфиг</span></h3>
<p><span></span><code class="language-text">Configuration</code><span>Объект является необязательным аргументом , который вы можете предоставить при инстанцировании </span><code class="language-text">embed</code><span>экземпляра:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">import { embed } from '@nebula.js/stardust';

const n = embed(enigmaApp, {
  context: {
    theme: 'dark',
  },
  types: [
    /* types */
  ],
});

n.render(/* chart 1*/);
n.render(/* chart 2*/);</pre>
<h3 id="reusable-config"><span>Многоразовая конфигурация</span></h3>
<p><span>Если вы работаете с несколькими приложениями или хотите иметь несколько разных конфигураций, вам может быть проще сначала создать конфигурации, а затем повторно использовать их.</span></p>
<p><span>Создайте файл, </span><code class="language-text">baseConfig</code><span>который выполняет тяжелую работу по регистрации типов и тем:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">const baseConfig = embed.createConfiguration({
  types: [
    /* register type once*/
  ],
  themes: [
    /* register themes once*/
  ],
});</pre>
<p><span>Создайте другую конфигурацию, которая наследуется от </span><code class="language-text">baseConfig</code><span>, примените </span><code class="language-text">'dark'</code><span>тему и установите ограничение, запрещающее выбор:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">const noSelectionDark = baseConfig.createConfiguration({
  context: {
    theme: 'dark',
    constraints: { select: true },
  },
});

// render chart with dark theme with no selections allowed
noSelectionDark(enigmaApp).render(/*chart config*/);
noSelectionDark(anotherEnigmaApp).render(/*chart config*/);</pre>
<p><span>Вы также можете напрямую привязать конфигурацию к приложению:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">const swedishPink = baseConfig(enigmaApp, {
  context: {
    theme: 'pinkish',
    language: 'sv-SE',
  },
});

swedishPink.render(/* chart config */);</pre>
<h3 id="registering-types"><span>Регистрация типов</span></h3>
<p><span>Перед визуализацией визуализации ее модуль необходимо загрузить и зарегистрировать. Вы можете загрузить необходимые модули из npm:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">$npm install @nebula.js/sn-bar-chart @nebula.js/sn-pie-chart</pre>
<p><span>А потом зарегистрируйте каждого </span><code class="language-text">type</code><span>индивидуально:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import barchart from '@nebula.js/sn-bar-chart';
import piechart from '@nebula.js/sn-pie-chart';

embed.createConfiguration({
  types: [
    {
      name: 'bar',
      load: () =&gt; Promise.resolve(barchart),
    },
    {
      name: 'pie',
      load: () =&gt; Promise.resolve(piechart),
    },
  ],
});</pre>
<h3 id="loading-on-the-fly"><span>Загрузка на лету</span></h3>
<p><span>Если вы точно не знаете, какие типы вам нужны, и не хотите устанавливать все, чтобы уменьшить размер вашего пакета, вы можете загрузить визуализации во время выполнения, используя облегченный загрузчик определений асинхронных модулей, например </span><a href="https://github.com/d3/d3-require"><span>d3-require</span></a><span> .</span></p>
<p><span>Начнем с установки модуля:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">npm install d3-require</pre>
<p><span>а затем настройте его для загрузки модулей из CDN, например </span><code class="language-text">https://unpkg.com</code><span>, а также укажите псевдоним для использования локальной версии </span><code class="language-text">@nebula.js/stardust</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">import { requireFrom } from 'd3-require';
import * as stardust from '@nebula.js/stardust';

const loadSnType = requireFrom((name) =&gt; `https://unpkg.com/@nebula.js/sn-${name}-chart`).alias({
  '@nebula.js/stardust': stardust,
});</pre>
<p><span>Затем вы можете настроить все типы, которые вы ожидаете использовать:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const types = ['bar', 'line', 'pie', 'sankey'].map((t) =&gt; ({
  type: t,
  load: () =&gt; loadSnType(t),
}));
const baseConfig = stardust.embed.createConfiguration({ types });</pre>
<p><span>Тип загружается с удаленного URL-адреса при первом отображении:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">baseConfig(enigmaApp).render({
  type: 'bar',
  fields: ['Product', '=sum(Sales)'],
});</pre>
<h3 id="context"><span>Контекст</span></h3>
<p><span>При настройке конфигурации вы можете применить, </span><code class="language-text">context</code><span>который контролирует язык, тему и ограничения в каждой визуализации, которую вы визуализируете:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">embed.createConfiguration({
  context: {},
});</pre>
<h4 id="constraints"><span>Ограничения</span></h4>
<p><span>Ограничения позволяют указать визуализации на отключение определенных типов взаимодействий и поведения.</span></p>
<p><span>Вы можете применить три различных ограничения:</span></p>
<ul>
<li><code class="language-text">passive</code><span>: отключить такие взаимодействия, как всплывающие подсказки.</span></li>
<li><code class="language-text">active</code><span>: отключение взаимодействий, влияющих на состояние визуального представления, таких как масштабирование, прокрутка и т. д.</span></li>
<li><code class="language-text">select</code><span>: выключить выделение.</span></li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  context: {
    constraints: {
      active: true,
      passive: true,
      select: true,
    },
  },
};</pre>
<p><code class="language-text">stardust</code><span> никоим образом не навязывает эти ограничения, вместо этого разработчик визуализации должен соблюдать и реализовывать их.</span></p>
<h4 id="language"><span>Язык</span></h4>
<p><code class="language-text">stardust</code><span> поддерживает 15 языков:</span></p>
<ul>
<li><code class="language-text">'en-US'</code><span> &#8211; Американский английский</span></li>
<li><code class="language-text">'sv-SE'</code><span> &#8211; шведский</span></li>
<li><code class="language-text">'it-IT'</code><span> &#8211; итальянский</span></li>
<li><code class="language-text">'zh-CN'</code><span> &#8211; Упрощенный китайский</span></li>
<li><code class="language-text">'zh-TW'</code><span> &#8211; Традиционный китайский</span></li>
<li><code class="language-text">'ko-KR'</code><span> &#8211; Корейский язык</span></li>
<li><code class="language-text">'de-DE'</code><span> &#8211; Немецкий</span></li>
<li><code class="language-text">'es-ES'</code><span> &#8211; Испанский</span></li>
<li><code class="language-text">'pt-BR'</code><span> &#8211; Бразильский португальский</span></li>
<li><code class="language-text">'ja-JP'</code><span> &#8211; Японский</span></li>
<li><code class="language-text">'fr-FR'</code><span> &#8211; Французкий язык</span></li>
<li><code class="language-text">'nl-NL'</code><span> &#8211; Голландский</span></li>
<li><code class="language-text">'tr-TR'</code><span> &#8211; Турецкий</span></li>
<li><code class="language-text">'pl-PL'</code><span> &#8211; польский</span></li>
<li><code class="language-text">'ru-RU'</code><span> &#8211; Русский</span></li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  context: {
    language: 'sv-SE',
  },
};</pre>
<h4 id="theme"><span>Тема</span></h4>
<p><span>Из коробки доступны две основные темы: </span><code class="language-text">'light'</code><span>и </span><code class="language-text">'dark'</code><span>.</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="js">{
  context: {
    theme: 'dark',
  }
};</pre>
<p><span>Светлая тема</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs.png"><img fetchpriority="high" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs.png" alt="" width="524" height="436" class="aligncenter size-full wp-image-2442" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs.png 524w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_light_nebulajs-300x250.png 300w" sizes="(max-width: 524px) 100vw, 524px" /></a></p>
<p><span>Темная тема</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs.png"><img decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs.png" alt="" width="523" height="434" class="aligncenter size-full wp-image-2443" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs.png 523w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_dark_nebulajs-300x249.png 300w" sizes="(max-width: 523px) 100vw, 523px" /><span></span></a></p>
<p><span>Вы также можете зарегистрировать собственные темы и применить одну из них в контексте:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  themes: [{
    id: 'pinkish',
    load: () =&gt; Promise.resolve({
      palettes: {
        data: [{
          scale: [
            '#fac6e5',
            '#ff95d6',
            '#e76eb1',
            '#b44772',
          ],
        }]
      }
    })
  }],
  context: {
    theme: 'pinkish'
  }
};</pre>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula.png"><img decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula.png" alt="" width="500" height="359" class="aligncenter size-full wp-image-2445" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula.png 500w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/theme_pinkish_nebula-300x215.png 300w" sizes="(max-width: 500px) 100vw, 500px" /></a></p>
<h2>Embedding visualizations. Встраивание визуализаций</h2>
<h3 data-testid="docs-header"><span>Встраивание визуализаций</span></h3>
<p><span>Вы можете встроить визуализацию двумя способами:</span></p>
<ol>
<li><span>На лету</span></li>
<li><span>Из существующего объекта</span></li>
</ol>
<p><span>Рендеринг выполняется с использованием </span><code class="language-text">render()</code><span>метода экземпляра, возвращаемого </span><code class="language-text">embed</code><span>функцией, который, как минимум, требует того, в который </span><code class="language-text">HTMLElement</code><span>вы хотите выполнить рендеринг:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { embed } from '@nebula.js/stardust';

const n = embed(enigmaApp);
n.render({
  element,
  // rest of the config
});</pre>
<h3 id="render-on-the-fly"><span>Рендеринг на лету</span></h3>
<p><span>При рендеринге визуализации на лету вам необходимо указать, что </span><code class="language-text">type</code><span> вы хотите визуализировать:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  type: 'barchart',
});</pre>
<p><span>Некоторые визуализации предъявляют минимальные требования к различным свойствам и / или данным, которые необходимо отображать, и в этом случае вы можете увидеть что-то вроде этого:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs.png"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs.png" alt="" width="747" height="489" class="aligncenter size-full wp-image-2447" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs.png 747w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/supernova_incomplete_nebulajs-300x196.png 300w" sizes="(max-width: 747px) 100vw, 747px" /></a></p>
<p><span>Чтобы предоставить визуализацию исходные данные, добавьте в </span><code class="language-text">fields</code><span>свойство измерения и меры данных :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  type: 'barchart',
  fields: ['Region', '=sum(Sales)'],
});</pre>
<p><span>Вы также можете изменить начальные свойства:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  type: 'barchart',
  fields: ['Product', '=sum(Sales)'],
  properties: {
    title: 'Sales by region',
  },
});</pre>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula.png"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula.png" alt="" width="773" height="529" class="aligncenter size-full wp-image-2448" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula.png 773w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula-300x205.png 300w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/barchart_nebula-768x526.png 768w" sizes="(max-width: 773px) 100vw, 773px" /></a></p>
<h2 id="render-from-existing-objects"><span>Рендеринг из существующих объектов</span></h2>
<p><span>Если вы уже создали общий объект в своем приложении и хотите его отобразить, вы можете сделать это, предоставив объекту </span><code class="language-text">id</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">n.render({
  element,
  id: '&lt;ObjectID&gt;',
});</pre>
<h2>Current app selections. Выборки текущего приложения</h2>
<p><span>Важной частью Qlik является фильтрация данных с помощью выборок. Большинство диаграмм поддерживают выбор в данных, которые они отображают, которые затем отфильтровывают данные и влияют на другие диаграммы, подключенные к той же модели данных.</span></p>
<h3 id="current-app-selections-bar"><span>Панель выбора текущего приложения</span></h3>
<p><span>На панели выбора текущего приложения отображаются активные в данный момент выборки в указанном приложении. Для рендеринга этого бара вам сначала понадобится </span><code class="language-text">HTMLElement</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">&lt;div class="curr-selections"&gt;&lt;/div&gt;</pre>
<p><span>Затем вы можете </span><code class="language-text">mount</code><span>выбрать пользовательский интерфейс в этом элементе:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const n = embed(enigmaApp);

(await n.selections()).mount(document.querySelector('.curr-selections'));</pre>
<p><span>Без каких-либо выделений должно получиться так:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar.png"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar.png" alt="" width="790" height="57" class="aligncenter size-full wp-image-2449" srcset="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar.png 790w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar-300x22.png 300w, https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/nebulajs_selectbar-768x55.png 768w" sizes="(max-width: 790px) 100vw, 790px" /></a></p>
<p><span>Когда вы начинаете применять выборки в различных диаграммах, пользовательский интерфейс обновляется, чтобы отразить текущее состояние:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_update.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_update.gif" alt="" width="792" height="520" class="aligncenter size-full wp-image-2450" /></a></p>
<h3 id="multiple-bars"><span>Несколько баров</span></h3>
<p><span>Если вы подключены к нескольким приложениям, вы можете отобразить текущий выбор в каждом из них, установив панель в разные элементы:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">(await embed(enigmaApp).selections()).mount(document.querySelector('.curr-selections'));

(await embed(anotherApp, { context: { theme: 'dark' } }).selections()).mount(
  document.querySelector('.another-curr-selections')
);</pre>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_multiple_barchart_nebulajs.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_multiple_barchart_nebulajs.gif" alt="" width="1020" height="428" class="aligncenter size-full wp-image-2451" /></a></p>
<h1>DEVELOPING VISUALIZATIONS. РАЗРАБОТКА ВИЗУАЛИЗАЦИЙ</h1>
<h2>Visualization. Визуализация</h2>
<h3 id="whats-a-visualization"><span>Что такое визуализация</span></h3>
<p><span>Визуализация в контексте этого API представляет собой визуальный вывод некоторых базовых данных, хранящихся в ассоциативной модели данных Qlik. Это может быть почти все, что вы хотите, и оно традиционно разработано для отображения данных в форме диаграммы, таблицы, kpi и т. Д.</span></p>
<p><strong>Визуализация состоит из двух основных частей: </strong></p>
<ul>
<li><span>backend <em>Generic Object</em></span><span>, который описывает </span><em><span>свойства</span></em><span> этого визуализация и сохраняется в модели данных, </span></li>
<li><span>и внешний интерфейс визуальной части, которая производит рендеринг <em>layout</em>  </span><span>из <em>Generic Object</em></span><span>.</span></li>
</ul>
<h4 id="definition"><span>Определение</span></h4>
<p><span>Минимальная визуализация, которая не содержит никаких данных и ничего не отображает, выглядит так:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">export default function () {
  return {
    qae: {
      /* */
    },
    component() {},
  };
}</pre>
<p><span>Здесь </span><code class="language-text">component()</code><span>вы визуализируете визуальную часть, а </span><code class="language-text">qae</code><span>здесь вы определяете свойства и данные, обрабатываемые ассоциативным механизмом Qlik (QAE).</span></p>
<h2>Rendering. Рендеринг</h2>
<p><span>В </span><code class="language-text">component</code><span>части определения происходит весь рендеринг, это просто функция, которая ничего не возвращает:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">export default function () {
  return {
    component() {
      // rendering logic goes here
    },
  };
}</pre>
<p><span>Чтобы отрендерить что-то, что вам нужно для доступа к элементу DOM, которому назначена визуализация, вы можете сделать это, импортировав </span><code class="language-text">useElement</code><span> функцию:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useElement } from '@nebula.js/stardust';</pre>
<p><span>Эта функция возвращает простой HTMLElement, который является вашей точкой входа в визуальный мир:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  const element = useElement();
  element.innerHTML = 'Hello!';
}</pre>
<p><code class="language-text">useElement</code><span>&#8211; это одна из многих функций, которые удовлетворяют наиболее распространенные требования при разработке визуализации, они позволяют </span><em><span>подключаться</span></em><span> к ресурсам, предоставляемым обеими </span><code class="language-text">stardust</code><span>сторонами и ассоциативным движком Qlik.</span></p>
<h3 id="hooks">Hooks</h3>
<p><span>Если вы работали с </span><a href="https://reactjs.org/"><span>React,</span></a><span> вы могли узнать это как </span><em><span>хуки</span></em><span> . Хуки &#8211; это концепция, в которой упор делается на многократно используемые составные функции, а не на классические объектно-ориентированные классы и наследование. Хотя реализация полностью настраивается с использованием настраиваемых хуков, концепция и правила очень похожи, настолько, что вы можете прочитать </span><a href="https://reactjs.org/docs/hooks-intro.html"><span>документацию</span></a><span> по <a href="https://reactjs.org/docs/hooks-intro.html">крючкам React,</a> чтобы понять, как использовать собственные хуки stardust.</span></p>
<h4 id="useelement">useElement</h4>
<p><span>Вы уже видели </span><code class="language-text">useElement</code><span>крючок, его единственная цель &#8211; предоставить HTMLElement, к которому вы должны прикрепить свои собственные элементы, чтобы сделать ваш контент видимым, в следующем примере для элемента </span><code class="language-text">innerHTML</code><span>установлено значение </span><code class="language-text">Hello!</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  // get the element
  const element = useElement();
  // set element content
  element.innerHTML = 'Hello!';
}</pre>
<p><span>Однако статическая строка не даст многого, в большинстве случаев вы обновляете контент на основе ввода данных, состояния компонентов и взаимодействия с пользователем.</span></p>
<p><span></span><code class="language-text">component()</code><span>Функция выполняется каждый раз , когда что &#8211; то , что может быть связано с вашими изменениями рендеринга; тема, модель данных, выбор данных, состояние компонента и т. д. Таким образом, добавление и удаление прослушивателей событий, обновление узлов DOM и выборка данных не идеальны и могут быть довольно тяжелыми для производительности, если делать это каждый раз при </span><code class="language-text">component()</code><span>запуске. Вместо этого вы должны выполнять пакетные обновления с </span><code class="language-text">useEffect</code><span>.</span></p>
<h4 id="useeffect"><span>useEffect</span></h4>
<p><code class="language-text">useEffect</code><span>&#8211; это ловушка, которая принимает функцию обратного вызова, которая запускается только при изменении указанного вами значения. Это позволяет не только выполнять пакетные обновления, но и реализовывать собственную форму управления жизненным циклом в вашем компоненте.</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useEffect } from '@nebula.js/stardust';
// ...
component() {
  const element = useElement();

  useEffect(() =&gt; {
    // run only once when the component is created
    console.log('created');
  }, []);
}</pre>
<p><span>Добавление слушателей событий к элементу обычно выполняется только при запуске компонента, а затем удаляется при его уничтожении:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  const element = useElement();

  useEffect(() =&gt; {
    const listener = () =&gt; {
      console.log('clicked');
    };

    element.addEventListener('click', listener);

    return () =&gt; {
      // clean-up
      element.removeEventListener('click', listener);
    };
  }, [element]);
}</pre>
<p><span>В предыдущем примере </span><code class="language-text">element</code><span>в качестве второго аргумента предоставляется наблюдаемое значение, поэтому эффект запускается только при </span><code class="language-text">element</code><span>изменении. Однако, поскольку </span><code class="language-text">element</code><span>никогда не изменяется для одного и того же компонента, обратный вызов запускается только один раз при создании компонента. Таким образом </span><code class="language-text">listener</code><span>, экземпляр может быть создан только один раз, и </span><code class="language-text">click</code><span>добавляется только один прослушиватель событий. Обратный вызов также возвращает функцию в конце, это функция очистки, которая выполняется при изменении любого из наблюдаемых значений или при уничтожении компонента. Здесь вы должны очистить все добавленные побочные эффекты, в этом случае прослушиватель событий удаляется, чтобы избежать утечки памяти.</span></p>
<h4 id="usestate"><span>useState</span></h4>
<p><span>Поскольку </span><code class="language-text">component()</code><span>это функция, а не экземпляр класса или объекта, вы не можете использовать его </span><code class="language-text">this</code><span>для хранения значений экземпляра, как в противном случае. Способ хранения состояния </span><code class="language-text">useState</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useState } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const [count, setCount] = useState(0);
    },
  };
}</pre>
<p><code class="language-text">useState</code><span>возвращает кортеж, в котором первый элемент совпадает с начальным значением, указанным в качестве аргумента </span><code class="language-text">useState</code><span>, а второй элемент является функцией установки, с помощью которой вы можете изменить значение.</span></p>
<p><span>В следующем примере </span><code class="language-text">count</code><span>увеличивается на 1, когда пользователь нажимает </span><code class="language-text">element</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">component() {
  const element = useElement();
  const [count, setCount] = useState(0);

  useEffect(() =&gt; {
    const listener = () =&gt; {
      setCount(count + 1);
    };

    element.addEventListener('click', listener);

    return () =&gt; {
      element.removeEventListener('click', listener);
    };
  }, [element]);
}</pre>
<p><span>Чтобы отобразить обновленное значение, вы можете добавить другое, </span><code class="language-text">useEffect</code><span>которое будет запускаться при </span><code class="language-text">count</code><span>изменении:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const [count, setCount] = useState(0);
useEffect(() =&gt; {
  element.innerHTML = `Count: ${count}`;
}, [count]);</pre>
<h2>Configuring data. Конфигурирование данных</h2>
<p><span>В </span><code class="language-text">qae</code><span>разделе определения вы определяете свойства универсального объекта и форму данных, которые вы ожидаете использовать.</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "qae": {
    "properties": {}
  }
}</pre>
<h3 id="generic-object"><span>Общий объект</span></h3>
<p><span>Каждая визуализация связана со всей моделью данных и ассоциативным механизмом Qlik через </span><em><span>универсальный объект</span></em><span> . Это объект JSON, содержащий </span><em><span>свойства, в</span></em><span> результате которых создается </span><em><span>макет</span></em><span> , описывающий состояние внутренней части визуализации.</span></p>
<p><span>Каждый раз, когда кто-то хочет визуализировать вашу визуализацию, в модели данных создается экземпляр универсального объекта. Если у создателя есть необходимые разрешения, он может сохранить и сохранить этот объект в своей модели данных.</span></p>
<h3 id="properties"><span>Свойства</span></h3>
<p><span>Какие свойства вы устанавливаете, полностью зависит от вас, однако это должен быть действительный объект JSON. Большинство свойств &#8211; это просто настройки, которые вы, возможно, захотите сохранить с течением времени. Если вы разрабатываете гистограмму, вы можете сохранить настройку, которая указывает, следует ли ее складывать или какой цвет должны иметь столбцы:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "isStacked": true,
  "barColor": "red"
}</pre>
<p><span>Эти свойства </span><em><span>статичны</span></em><span> , то, что входит, выходит точно так же. Истинная сила универсального объекта &#8211; это </span><em><span>динамические</span></em><span> свойства, которые вы можете установить, что позволяет вам использовать ассоциативный механизм Qlik и получать доступ к данным внутри него.</span></p>
<p><span>Динамические свойства имеют особую структуру, которая позволяет серверной части различать динамические и статические свойства. У них также есть соглашение об именах: все они начинаются с </span><code class="language-text">q</code><span>буквы, за которой следует заглавная буква, что позволяет людям и машинам легко различать два типа свойств.</span></p>
<p><span>Существует множество различных </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas"><span>предопределенных</span></a><span> динамических свойств для различных целей, например, вы можете использовать </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FValueExpression"><span>ValueExpression</span></a><span> для выполнения простых вычислений:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "simpleMath": {
    "qValueExpression": {
      "qExpr": "1+1"
    }
  }
}</pre>
<h4 id="layout">Layout (Макет/Слой)</h4>
<p><span><em>layout </em>из Generic Object является результатом статических и динамических свойств. layout предыдущих свойств выглядит следующим образом:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "isStacked": true,
  "barColor": "red",
  "simpleMath": 2
}</pre>
<p><span>Обратите внимание, что статические свойства остаются точно такими же, в то время как динамическое свойство </span><code class=" language-text">simpleMath</code><span>теперь содержит вычисленный результат ValueExpression.</span></p>
<p><span>Большинство динамических свойств имеют определение ввода и соответствующий вывод макета; а </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FListObjectDef"><span>ListObjectDef</span></a><span> приводит к </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FListObject"><span>ListObject</span></a><span> , а </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FSelectionObjectDef"><span>SelectionObjectDef</span></a><span> результаты в </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FSelectionObject"><span>SelectionObject</span></a><span> , и так далее.</span></p>
<h3 id="data"><span>Данные</span></h3>
<p><span>Наиболее часто используемым определением свойства является </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FHyperCubeDef"><span>HyperCubeDef</span></a><span> , это динамическое свойство, которое предоставляет вам данные из внутренней модели данных. Вы можете разместить это в корне объекта свойств или на более глубоком уровне, и у вас может быть столько, сколько вам нужно:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "qHyperCubeDef": {},
  "anotherOne": {
    "qHyperCubeDef": {},
    "andAThird": {
      "qHyperCubeDef": {}
    }
  }
}</pre>
<p><span>Основными входными данными HyperCubeDef являются </span><em><span>измерения</span></em><span> и </span><em><span>меры</span></em><span> :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  "qHyperCubeDef": {
    "qDimensions": [{ "qLibraryId": "hdg534" }],
    "qMeasures": [{ "qLibraryId": "gt5dgd" }]
  }
}</pre>
<p><span>В этом случае измерения и меры жестко запрограммированы на предопределенное значение, которое может существовать в определенной модели данных, что редко бывает тем, что вам нужно. Если вы разрабатываете диаграмму для использования другими с какой-либо моделью данных, которая вам нужна, чтобы можно было добавлять их динамически, вы можете сделать это, указав </span><em><span>целевые объекты данных</span></em><span> .</span></p>
<h4 id="data-targets"><span>Цели данных</span></h4>
<p><span>Целевой объект данных &#8211; это способ определить, где расположены динамические HyperCubeDef в свойствах универсального объекта. Хотя вы </span><code class=" language-text">stardust</code><span>можете просматривать свойства и находить все их использования </span><code class=" language-text">qHyperCubeDef</code><span>, вы можете не захотеть, чтобы все они были динамическими, или вы можете сгенерировать их только для внутреннего использования.</span></p>
<p><span>Вы указываете целевые объекты данных с помощью </span><code class=" language-text">data.targets</code><span>ключа </span><code class=" language-text">qae</code><span>, каждая цель должна иметь </span><code class=" language-text">path</code><span>ключ, который указывает путь JSON к HyperCubeDef из корня объекта свойств:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qae: {
  properties: {
    qHyperCubeDef: {},
    my: {
      nested: {
        qHyperCubeDef: {}
      },
    }
  },
  data: {
    targets: [
      { path: '/qHyperCubeDef' },
      { path: '/my/nested/qHyperCubeDef' },
    ];
  }
}</pre>
<p><span>Вы можете для каждого целевого объекта данных указать дополнительные сведения, такие как максимальное / минимальное количество измерений и мер, и внести изменения при их добавлении.</span></p>
<p><span>Это полезно, когда вы знаете ограничения того, что может отображать диаграмма. Например, круговая диаграмма в основном используется, когда у нее есть ровно одно измерение и одна мера, но вы также можете реализовать поддержку второй меры. Это также избавляет вас от некоторой логики кода, поскольку </span><code class=" language-text">stardust</code><span>не пытается отобразить диаграмму, ограничения которой не были выполнены, а вместо этого показывает, что некоторые поля отсутствуют.</span></p>
<h4 id="field-limitations">Field limitations. <span>Ограничения поля</span></h4>
<p><span>Чтобы указать ограничения для измерений или показателей, добавьте каждый соответствующий тип поля как объект как часть целевого объекта данных:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">targets: [
  {
    path: '/qHyperCubeDef',
    dimensions: {
      min: 1,
      max: 1,
    },
    measures: {
      min: 1,
      max: 2,
    },
  },
];</pre>
<h3 id="field-modifications">Field modifications</h3>
<p><span>Вы также можете изменить добавленное или удаленное поле непосредственно перед тем, как изменение будет применено и отправлено на серверную часть, это полезно для таких вещей, как настройка сортировки при добавлении измерения или добавление дополнительных свойств, которые, как вы знаете, всегда необходимы.</span></p>
<p><span>Если вы, например, хотите убедиться, что нулевые значения подавляются, поскольку это не то, что вы можете визуализировать или представить в хорошем виде, вы можете установить, </span><code class=" language-text">qNullSuppression: true</code><span>когда добавляется измерение:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">dimensions: {
  added(dimension) {
    dimension.qNullSuppression = true;
  }
}</pre>
<h2>Consuming data. Потребление данных</h2>
<h3 id="access-layout">Access layout</h3>
<p><span>Вы можете получить доступ к <em>layout</em> Generic Object</span><span> через набор предопределенных hooks.</span></p>
<h4 id="uselayout">useLayout</h4>
<p><code class="language-text">useLayout</code><span> возвращает </span>evaluated layout свойств Generic Object:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useLayout } from '@nebula.js/stardust';

export default function () {
  return {
    qae: {
      properties: {
        qHyperCubeDef: {},
        simpleMath: {
          qValueExpression: {
            qExpr: '1+1',
          },
        },
      },
    },
    component() {
      const layout = useLayout();
      console.log(layout); // { qHyperCube: {/* HyperCube Layout */}, simpleMath: 2 }
    },
  };
}</pre>
<p><span>Вы должны </span><code class="language-text">useEffect</code><span>при наблюдении изменений на </span><code class="language-text">layout</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">const layout = useLayout();

useEffect(() =&gt; {
  // do some heavy update
}, [layout]);</pre>
<h4 id="useapplayout">useAppLayout</h4>
<p><code class="language-text">useAppLayout</code><span>возвращает </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FNxAppLayout"><span>NxAppLayout,</span></a><span> к <a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FNxAppLayout">которому</a> вы в данный момент подключены:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useAppLayout } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const appLayout = useAppLayout();
      console.log(appLayout); // { qTitle: 'App title', qLocaleInfo: {/* */ } }
    },
  };
}</pre>
<p><span>Наиболее распространенный вариант использования макета приложения &#8211; это доступ, </span><code class="language-text">qLocaleInfo</code><span>который содержит сведения о локали, выбранные владельцем приложения и должен использоваться для форматирования чисел.</span></p>
<h3 id="models">Models. <span>Модели</span></h3>
<p><span>Помимо макетов приложения и универсального объекта, у вас есть полный доступ к API, созданным с помощью </span><code class="language-text">enigma.js</code><span>. Эти API-интерфейсы генерируются из схемы JSON-RPC и раскрывают всю мощь Associate Engine Qlik.</span></p>
<h4 id="usemodel"><span>useModel</span></h4>
<p><code class="language-text">useModel</code><span>возвращает сгенерированный API </span><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject"><span>Generic Object</span></a><span> :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const model = useModel();
      model.getInfo().then((info) =&gt; {
        console.log(info);
      });
    },
  };
}</pre>
<p><span>Общие операции в этом API:</span></p>
<ul>
<li><span>делать выбор с помощью </span><code class="language-text">beginSelections</code><span>,  </span><code class="language-text">selectHyperCubeValues</code> и <code class="language-text">endSelections</code></li>
<li><span>получить больше данных с </span><code class="language-text">getHyperCubeData</code></li>
</ul>
<h4 id="useapp"><span>useApp</span></h4>
<p><code class="language-text">useApp</code><span>возвращает сгенерированный API <a href="https://qlik.dev/apis/json-rpc/qix/doc#%23%2Fentries%2FDoc">Doc</a>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useApp } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const app = useApp();
      app.clearAll();
    },
  };
}</pre>
<p><span>Общие операции в этом API:</span></p>
<ul>
<li><span>изменять стек выбора с </span><code class="language-text">clearAll</code><span>,  </span><code class="language-text">back</code><span>,</span><code class="language-text">forward</code></li>
<li><span>создавать и применять закладки с помощью </span><code class="language-text">createBookmark</code> и <code class="language-text">applyBookmark</code></li>
</ul>
<h3 id="useglobal"><span>useGlobal</span></h3>
<p><code class="language-text">useGlobal</code><span>возвращает сгенерированный API </span><a href="https://qlik.dev/apis/json-rpc/qix/global#%23%2Fentries%2FGlobal"><span>Global</span></a><span> :</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useGlobal } from '@nebula.js/stardust';

export default function () {
  return {
    component() {
      const g = useGlobal();
      g.engineVersion().then((v) =&gt; {
        console.log(v);
      });
    },
  };
}</pre>
<p><span>Общие операции в этом API:</span></p>
<ul>
<li><span>получить список приложений с </span><code class="language-text">getDocList</code></li>
</ul>
<h2>HyperCube introduction. Введение в HyperCube</h2>
<p><span>Это </span><code class="language-text">HyperCubeDef</code><span>фундаментальная структура, которую вы настраиваете, прежде чем вам будет предоставлен результат в виде файла </span><code class="language-text">HyperCube</code><span>. Не позволяйте имени пугать вас, хотя оно содержит множество свойств и может быть настроено разными способами, в своей основной форме оно напоминает простую таблицу со строками и столбцами.</span></p>
<h3 id="hypercubedef-configuration"><span>Конфигурация HyperCubeDef</span></h3>
<p><span>Не все свойства одинаково важны, и есть несколько ключевых, о которых нужно помнить при настройке </span><code class="language-text">HyperCubeDef</code><span>.</span></p>
<h4 id="qmode"><span>qMode</span></h4>
<p><span>Хотя вам может не потребоваться </span><code class="language-text">qMode</code><span>явно устанавливать, поскольку по умолчанию используется простейший режим </span><code class="language-text">'S'</code><span>, важно знать, какое влияние он оказывает на структуру данных.</span></p>
<p><code class="language-text">qMode: 'P'</code><span>, или </span><em><span>режим</span></em><span> сводной таблицы, дает вам структуру, подходящую для представления сводных таблиц с группами как в вертикальном, так и в горизонтальном направлениях, а также группы для всех показателей.</span></p>
<p><code class="language-text">qMode: 'T'</code><span>, или </span><em><span>древовидный режим</span></em><span> , дает вам структуру, напоминающую дерево и подходящую для визуализации древовидных визуализаций; древовидная карта, упаковка кругов, солнечные лучи, дендрограмма, решётка и т. д.</span></p>
<p><code class="language-text">qMode: 'S'</code><span>, или </span><em><span>прямой режим</span></em><span> , является самым простым из них и дает вам структуру данных, которая выглядит как простая таблица со строками и столбцами. Для простоты объяснения остальной части гиперкуба можно предположить, что он используется.</span></p>
<h4 id="qdimensions-and-qmeasures"><span>qDimensions и qMeasures</span></h4>
<p><code class="language-text">qDimensions</code><span>и </span><code class="language-text">qMeasures</code><span>являются столбцами вашей «таблицы», нет явного ограничения на их количество, которое вы можете добавить, но часто существует ограничение на количество измерений и мер, которые может обрабатывать определенная диаграмма, и вам нужно сохранить это количество из них в виду, когда вы укажете </span><code class="language-text">qInitialDataFetch</code><span>.</span></p>
<h4 id="qinitialdatafetch"><span>qInitialDataFetch</span></h4>
<p><span>Ассоциативный движок Qlik &#8211; это решение на основе памяти, что означает, что объем данных, которые он может обрабатывать, полностью зависит от ресурсов памяти, к которым у него есть доступ. Таким образом, он может содержать миллиарды значений данных, и поэтому количество строк в гиперкубе также потенциально может достигать миллиардов.</span></p>
<p><span>Чтобы избежать случаев, когда такие огромные объемы данных передаются в интерфейсную часть, гиперкуб по умолчанию вообще не включает никаких строк. Чтобы контролировать это, вы можете установить количество строк и столбцов, которое вы хотите изначально </span><code class="language-text">qInitialDataFetch</code><span>. Это свойство позволяет вам установить </span><em><span>страницы данных, которые</span></em><span> вы хотите извлечь из всего гиперкуба, поэтому вы можете, например, выбрать получение первых 50 строк:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qHyperCubeDef: {
  qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 50, qWidth: 4 }];
}</pre>
<p><span>Если вы думаете о прямой таблице как о сетке, из которой вы хотите извлечь некоторые данные, тогда </span><code class="language-text">qLeft</code><span>и </span><code class="language-text">qTop</code><span>&#8211; это верхний левый угол подмножества, которое вы хотите извлечь, а </span><code class="language-text">qHeight</code><span>и </span><code class="language-text">qWidth</code><span>&#8211; количество строк и столбцов.</span></p>
<p><span>Однако существует максимальный предел в 10 000 ячеек, которые вы можете извлечь за один раз, и это количество вызывает ошибку. Поэтому вам нужно следить за количеством столбцов может потребоваться для обеспечения общей не превышает 10 000. Если вы, например , знаете , что вы никогда не нужно больше , чем 4 колонки, то вы можете установить </span><code class="language-text">qHeight</code><span>на </span><code class="language-text">10000/4</code><span>:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qInitialDataFetch: [{ qLeft: 0, qTop: 0, qHeight: 2500, qWidth: 4 }];</pre>
<p><span>Первоначальная выборка данных указывает только самую большую возможную часть всего гиперкуба в макете, если в гиперкубе всего 7 строк, вы не получите больше 7. Вы также можете динамически получать больше данных позже.</span></p>
<h3 id="consuming-the-hypercube"><span>Потребление HyperCube</span></h3>
<p><span>Выход, или </span><em><span>компоновка</span></em><span> , из </span><code class=" language-text">HyperCubeDef</code><span>является </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FHyperCube"><span>гиперкубом</span></a><span> . В макете он расположен в том же месте, что и вы определили в своих свойствах, но без </span><code class=" language-text">Def</code><span>, например ввода:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  properties: {
    qHyperCubeDef: {},
    another: {
      one: {
        qHyperCubeDef: {}
      }
    }
  }
}</pre>
<p><span>приводит к выводу:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">{
  layout: {
    qHyperCube: {},
    another: {
      one: {
        qHyperCube: {}
      }
    }
  }
}</pre>
<p><span>Рядом с </span><code class=" language-text">qDimensionInfo</code><span>и </span><code class=" language-text">qMeasureInfo</code><span>свойствами , которые содержат ваши размеры и меры, наиболее важную часть гиперкуба являются </span><em><span>страницы данных</span></em><span> .</span></p>
<h4 id="data-pages"><span>Страницы данных</span></h4>
<p><span>На страницах данных содержатся фактические значения данных гиперкуба, где именно и какая структура они имеют, зависит от </span><code class=" language-text">qMode</code><span>значения, которое вы установили ранее. Для режима </span><code class=" language-text">'S'</code><span>это место </span><code class=" language-text">qDataPages</code><span>, которое, в свою очередь, содержит </span><code class=" language-text">qArea</code><span>и </span><code class=" language-text">qMatrix</code><span>.</span></p>
<p><span>Предполагая, что гиперкуб содержит одно измерение, </span><em><span>название фильма</span></em><span> , и одну меру, </span><em><span>средний рейтинг</span></em><span> , содержимое может выглядеть следующим образом:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">qDataPages: [
  {
    qMatrix: [
      [
        // first row
        { qText: '2 Fast 2 Furious', qNum: 'NaN', qElemNumber: 447, qState: 'O' }, // NxCell
        { qText: '6.2', qNum: 6.2, qElemNumber: 0, qState: 'L' },
      ],
      [
        // second
        { qText: '2 Guns', qNum: 'NaN', qElemNumber: 681, qState: 'O' },
        { qText: '6.6', qNum: 6.6, qElemNumber: 0, qState: 'L' },
      ],
    ],
    qArea: { qTop: 0, qLeft: 0, qWidth: 2, qHeight: 2 },
  },
];</pre>
<p><span>Помимо текстовых и числовых значений, каждая </span><a href="https://qlik.dev/apis/json-rpc/qix/schemas#%23%2Fdefinitions%2Fschemas%2Fentries%2FNxCell"><span>ячейка NxCell</span></a><span> содержит </span><code class=" language-text">qElemNumber</code><span>свойство, известное как </span><em><span>ранг</span></em><span> . Ранг для ячейки измерения можно рассматривать как свойство, которое однозначно идентифицирует текстовое значение этой ячейки в своем поле во всей модели данных. Вы можете использовать это свойство для обеспечения единообразного поведения во всем приложении, вы можете, например, установить постоянный цвет значений измерения в поле, когда и где бы они ни использовались:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">// color scheme
const colors = ['#26A0A7', '#79D69F', '#F9EC86', '#EC983D'];

const cellColor = colors[cell.qElemNumber % colors.length];</pre>
<p><span>Это свойство также необходимо отслеживать, когда вы хотите сделать выбор в своей диаграмме.</span></p>
<h4 id="getting-more-data"><span>Получение дополнительных данных</span></h4>
<p><span>Из-за ограничения объема данных, которые вы можете получить в исходном макете, могут возникнуть ситуации, когда вам потребуется получить остальные данные, если вы хотите отобразить их больше. Вы можете сделать это с помощью методов, представленных в </span><em><span>модели</span></em><span> универсального объекта. Какой метод использовать, опять же, зависит </span><code class=" language-text">qMode</code><span>от гиперкуба, для </span><code class=" language-text">'S'</code><span>режима это </span><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeData"><span>GetHyperCubeData</span></a><span> .</span></p>
<p><span>При подкачке данных в прямом режиме вы должны начать с просмотра </span><code class=" language-text">qHyperCubeDef.qSize</code><span>свойства, которое содержит информацию о ширине и высоте полного гиперкуба. Исходя из этого, вы можете рассчитать количество страниц, которые вам нужно получить:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel, useLayout, useEffect } from '@nebula.js/stardust';

const NUM_CELLS_PER_PAGE = 10000;
const MAX_PAGES = 10;
// ...
component() {
  const model = useModel();
  const layout = useLayout();

  useEffect(() =&gt; {
    const Y = layout.qHyperCube.qSize.qcy;
    const X = layout.qHyperCube.qSize.qcx;

    const HEIGHT_PER_PAGE = Math.ceil(NUM_CELLS_PER_PAGE / X);
    const NUM_PAGES = Math.floor(MAX_PAGES, Math.ceil(Y / HEIGHT_PER_PAGE));

    const pagesToFetch = [];
    for (let i = 0; i &lt; NUM_PAGES; i++) {
      pagesToFetch.push({ qLeft: 0, qTop: i * HEIGHT_PER_PAGE, qHeight: HEIGHT_PER_PAGE, qWidth: X });
    }

    Promise.all(pagesToFetch.map((page) =&gt; model.getHyperCubeData('/qHyperCubeDef', [page]))).then((pages) =&gt; {
      console.log(pages);
    });
  }, [layout]);

}</pre>
<p><span>Однако вы должны быть </span><strong><span>очень</span></strong><span> осторожны при динамической выборке таких данных, имейте в виду, что размер куба может исчисляться миллионами, выборка такого большого набора данных может занять время и создать очень плохое взаимодействие с пользователем. В предыдущем примере максимальное количество страниц установлено равным 10, так что всего выбирается не более 100 000 значений.</span></p>
<p><span>Вы также можете использовать другие методы, чтобы не получать все данные сразу. </span><em><span>Виртуальная прокрутка</span></em><span> в сочетании с регулированием каждого запроса может значительно повысить производительность. Вам также следует рассмотреть возможность использования сокращенного набора данных, если вам не нужны точные значения:</span></p>
<ul>
<li><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeBinnedData"><span>getHyperCubeBinnedData</span></a><span> связывает точки данных в группы и отлично подходит для тепловых карт и 2D-графиков плотности.</span></li>
<li><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeContinuousData"><span>getHyperCubeContinuousData</span></a><span> уменьшает количество точек в непрерывном измерении и отлично подходит для временных данных.</span></li>
<li><a href="https://qlik.dev/apis/json-rpc/qix/genericobject#%23%2Fentries%2FGenericObject%2Fentries%2FGetHyperCubeReducedData"><span>getHyperCubeReducedData</span></a><span> выполняет некоторую магию вейвлетов и отлично подходит для мини-диаграмм.</span></li>
</ul>
<h2>Selecting data. Выбор данных</h2>
<p><span>Выборка &#8211; это фундаментальная часть ассоциативного механизма Qlik. Все поля и связи между ними содержатся в ассоциативной модели. Когда вы применяете выбор, вы не только применяете фильтр в модели данных, но также демонстрируете связи между вашими источниками данных.</span></p>
<h3 id="applying-selections"><span>Applying selections. </span><span>Применение выделений</span></h3>
<p><span>Выборки можно применять с помощью методов, представленных в модели, возвращенной из </span><code class="language-text">useModel</code><span>хука.</span></p>
<p><span>Поскольку универсальный объект может содержать несколько гиперкубов, вам всегда нужно указать, какой гиперкуб вы хотите выбрать, указав его путь JSON в качестве первого аргумента:</span></p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel } from '@nebula.js/stardust';
// ...
component() {
  const model = useModel();

  useEffect(() =&gt; {
    model.selectHyperCubeCells('/qHyperCubeDef', [1], []);
  }, [model])
}</pre>
<h3 id="selection-patterns"><span>Шаблоны выбора. Selection patterns</span></h3>
<p><span>Есть два разных шаблона выбора: мгновенный и модальный.</span></p>
<h4 id="instant-selections"><span>Мгновенный выбор. Instant selections</span></h4>
<p><span>Как видно из названия, этот тип шаблона является немедленным и фильтрует как источник выбора, так и все, на что он влияет.</span></p>
<p><span>В следующем примере, как только значение выбрано на гистограмме, фильтрация применяется мгновенно, и обе диаграммы немедленно обновляются отфильтрованными данными:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_instant_qlik_sense_nebula_js_nebulajs_api.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_instant_qlik_sense_nebula_js_nebulajs_api.gif" alt="" width="912" height="388" class="aligncenter size-full wp-image-2460" /></a></p>
<h4 id="modal-selections"><span>Модальный выбор. Modal selections</span></h4>
<p><span>Когда инициируется модальный выбор, источник выбора входит в форму модального состояния, которое позволяет пользователю изменять выбор до подтверждения изменений.</span></p>
<p><span>В следующем примере пользователь сначала выбирает одно значение на линейчатой ​​диаграмме, после чего другие диаграммы обновляются, как и раньше. Однако гистограмма по-прежнему содержит все доступные данные и позволяет пользователю выбрать другое значение перед подтверждением изменений и обновлением самой гистограммы:</span></p>
<p><a href="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_modal_qlik_sense_nebula_js_nebulajs_api.gif"><img loading="lazy" decoding="async" src="https://qliksense.ivan-shamaev.ru/wp-content/uploads/2020/11/selections_modal_qlik_sense_nebula_js_nebulajs_api.gif" alt="" width="912" height="388" class="aligncenter size-full wp-image-2462" /></a></p>
<p><span>Чтобы реализовать этот тип паттерна, вам необходимо выполнить несколько простых шагов </span><code class=" language-text">useSelections</code><span>в сочетании с </span><code class=" language-text">useModel</code><span>ними:</span></p>
<ol>
<li><span>Войдите в модальное состояние, позвонив </span><code class=" language-text">beginSelections</code><span>.</span></li>
<li><span>Выберите значения.</span></li>
<li><span>Обеспечьте визуальную обратную связь с пользователем о том, что было выбрано, например, изменив прозрачность выбранных значений.</span></li>
<li><span>Следите за выходом из модального состояния, чтобы сбросить визуальную обратную связь.</span></li>
</ol>
<pre class="EnlighterJSRAW" data-enlighter-language="generic">import { useModel, useSelections, useElement } from '@nebula.js/stardust';
// ...
component() {
  const element = useElement();
  const model = useModel();
  const selections = useSelections();

  useEffect(() =&gt; {
    const clicked = () =&gt; {
      const clickedOnRow = 1;

      // 1. enter modal state if not already in it
      if (!selections.isActive()) {
        selections.beginSelections(['/qHyperCubeDef']);
      }
      // 2. select the clicked row
      model.selectHyperCubeCells('/qHyperCubeDef', [clickedOnRow], []);
    }

    element.addEventListener('click', clicked);
    return () =&gt; {
      element.removeEventListener('click', clicked);
    }
  }, [element, model, selections]);

  useEffect(() =&gt; {
    if (layout.qSelectionInfo.qInSelections) {
      // 3. update with visual feedback on active selections
      // YOUR CODE HERE
    } else {
      // 4. normal update
      // YOUR CODE HERE
    }
  }, [layout]);
}</pre>
<p>&nbsp;</p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/">nebula.js &#8211; Qlik Sense API Javascript библиотека. Примеры</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://qliksense.ivan-shamaev.ru/nebula-js-qlik-sense-api-javascript-library-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Разработка web приложений AngularJS &#038; Qlik Sense API. Frontend &#038; Backend</title>
		<link>https://qliksense.ivan-shamaev.ru/web-application-development-angularjs-qlik-api/</link>
					<comments>https://qliksense.ivan-shamaev.ru/web-application-development-angularjs-qlik-api/#respond</comments>
		
		<dc:creator><![CDATA[qliksense-expert]]></dc:creator>
		<pubDate>Wed, 09 Oct 2019 03:23:51 +0000</pubDate>
				<category><![CDATA[Уровень 2]]></category>
		<category><![CDATA[angular.js qlik engine api]]></category>
		<category><![CDATA[angular.js qlik sense engine api]]></category>
		<category><![CDATA[angularjs]]></category>
		<category><![CDATA[API Qlik Engine]]></category>
		<category><![CDATA[javascript qlik sense]]></category>
		<category><![CDATA[qlik sense engine api]]></category>
		<category><![CDATA[Qlik Sense Mashup]]></category>
		<guid isPermaLink="false">https://qliksense.ivan-shamaev.ru/?p=1752</guid>

					<description><![CDATA[<p>Краткий 5 минутное AngularJS Guide для Qlik Sense Developer Angular.js сравнительно новый проект в мире JavaScript фреймворков. Впервые он был представлен в 2012 году сотрудником Google, и с тех пор стал проектом, поддерживаемым Google. Его цель &#8211; упростить одностраничные приложения, предоставив разработчикам MVC-подобную структуру для JavaScript. Он в основном работает,<a class="moretag" href="https://qliksense.ivan-shamaev.ru/web-application-development-angularjs-qlik-api/"> Читать дальше&#8230;</a></p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/web-application-development-angularjs-qlik-api/">Разработка web приложений AngularJS &#038; Qlik Sense API. Frontend &#038; Backend</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Краткий 5 минутное AngularJS Guide для Qlik Sense Developer</h2>



<p><strong>Angular.js</strong> сравнительно новый проект в мире JavaScript фреймворков. Впервые он был представлен в 2012 году сотрудником Google, и с тех пор стал проектом, поддерживаемым Google. Его цель &#8211; упростить одностраничные приложения, предоставив разработчикам MVC-подобную структуру для JavaScript. Он в основном работает, предоставляя пользовательские теги HTML, которые помогают связывать элементы DOM с моделью, через переменные JavaScript или данные JSON. Вы можете лучше использовать свой JavaScript, разбив его на контроллеры, а также модули.</p>
<p>С Angular вы получаете более чистый код JavaScript и автоматическое двухстороннее связывание данных, что идеально подходит для тяжелых сайтов AJAX.</p>
<h3><span>Скачать Angular</span></h3>
<p>Начнем с добавления Angular.js в наши проекты, поэтому зайдите на сайт <a href="http://angularjs.org" target="_blank" rel="noopener noreferrer">http://angularjs.org</a> и загрузите копию файла js в свой проект (директория с файлами html). Добавьте в разделе Head обращение к файлу js.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="null">&lt;script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"&gt;&lt;/script&gt;</pre>
<h2>Создайте файл Javascript с именем app.js</h2>
<p>&#8230;</p>
<p>https://www.thatsoftwaredude.com/content/6100/a-quick-5-minute-guide-to-angular-js</p>



<h2 class="wp-block-heading">Использование Angular.JS для работы с Qlik Sense Engine API</h2>



<p><span class="strong"><strong><span>AngularJS</span></strong></span><span> является структурной основой</span><span> для </span><span>построения динамических веб-приложений на JavaScript. Он расширяет классический синтаксис HTML, внедряя динамические angular выражения (angular expressions), которые обновляют или модифицируют DOM на основе кода. Он очень удобен для динамического связывания данных на веб-странице HTML (отправка данных на страницу и отправка данных к api). <strong>Qlik Sense&#8217;s native Straight Table</strong> (стандартная прямая таблица) была разработана на основе Angular.</span></p>
<p><span>Как и любая полезная библиотека, AngularJS упрощает разработку приложений, предоставляя разработчику более высокий уровень абстракции написания кода.</span></p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/web-application-development-angularjs-qlik-api/">Разработка web приложений AngularJS &#038; Qlik Sense API. Frontend &#038; Backend</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://qliksense.ivan-shamaev.ru/web-application-development-angularjs-qlik-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Qlik Sense Extension &#038; Mashup Tutorial</title>
		<link>https://qliksense.ivan-shamaev.ru/qlik-sense-extension-mashup-tutorial/</link>
					<comments>https://qliksense.ivan-shamaev.ru/qlik-sense-extension-mashup-tutorial/#respond</comments>
		
		<dc:creator><![CDATA[qliksense-expert]]></dc:creator>
		<pubDate>Wed, 03 Oct 2018 13:28:21 +0000</pubDate>
				<category><![CDATA[Youtube подборки видео по тематикам Qlik Sense]]></category>
		<category><![CDATA[Navigation API]]></category>
		<category><![CDATA[Qlik]]></category>
		<category><![CDATA[qlik sense]]></category>
		<category><![CDATA[Qlik Sense Extension]]></category>
		<category><![CDATA[Qlik Sense Mashup]]></category>
		<category><![CDATA[qliksense]]></category>
		<category><![CDATA[Root Api]]></category>
		<category><![CDATA[youtube]]></category>
		<guid isPermaLink="false">https://qliksense.ivan-shamaev.ru/?p=324</guid>

					<description><![CDATA[<p>Осторожно! Индусский английский ? #1 Basic Qlik Sense Extension #2 Make Kpi object In Qlik Sense Extension #3 Qlik Sense Navigation API #4 How to make legend extension using HTML and CSS in Qlik Sense #5 How to use Bootstrap in Qlik Sense Mashup #6 Root Api Part 1 #7 Basic<a class="moretag" href="https://qliksense.ivan-shamaev.ru/qlik-sense-extension-mashup-tutorial/"> Читать дальше&#8230;</a></p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/qlik-sense-extension-mashup-tutorial/">Qlik Sense Extension &#038; Mashup Tutorial</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="color: #ff6600;"><strong>Осторожно! Индусский английский</strong></span> <span>?</span></p>
<h2><strong>#1 Basic Qlik Sense Extension</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/8zYjzJwGb9Y?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#2 Make Kpi object In Qlik Sense Extension</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/jdL-hbbNo_g?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#3 Qlik Sense Navigation API</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/gZBxJxYBs1k?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#4 How to make legend extension using HTML and CSS in Qlik Sense</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/zFdXZWUtqYE?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#5 How to use Bootstrap in Qlik Sense Mashup</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/twpXSZviMn4?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#6 Root Api Part 1</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/CMdoyFF88FU?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#7 Basic Mashup Using Template</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/dXkM0TWMoF4?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#8 Basic Export Method</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/Ppz27X1TrIA?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#9 Make Trigger in Qlik Sense Part 1</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/WDpXigb-kDc?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#10 Make Trigger in Qlik Sense Part 2</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/YXXR5FAeuW4?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<h2><strong>#11 Make Trigger in Qlik Sense Part 3</strong></h2>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/guvh05eFyhU?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen="allowfullscreen"></iframe></p>
<p>Сообщение <a href="https://qliksense.ivan-shamaev.ru/qlik-sense-extension-mashup-tutorial/">Qlik Sense Extension &#038; Mashup Tutorial</a> появились сначала на <a href="https://qliksense.ivan-shamaev.ru">Qlik Sense - Обучение, учебник, онлайн курс</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://qliksense.ivan-shamaev.ru/qlik-sense-extension-mashup-tutorial/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
