All pages added

pull/3420/head
Bahadir Sofuoglu 2022-09-09 23:41:18 +03:00
parent 53f89e68b7
commit 4d55806088
260 changed files with 94107 additions and 1 deletions

108
package-lock.json generated
View File

@ -12,6 +12,8 @@
"@fullcalendar/timegrid": "^5.7.2",
"@fullcalendar/vue3": "^5.7.2",
"@vitejs/plugin-vue-jsx": "^2.0.1",
"@vuelidate/core": "^2.0.0-alpha.14",
"@vuelidate/validators": "^2.0.0-alpha.12",
"chart.js": "3.3.2",
"nuxt": "3.0.0-rc.9",
"primeflex": "^3.2.1",
@ -1519,6 +1521,76 @@
"integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==",
"dev": true
},
"node_modules/@vuelidate/core": {
"version": "2.0.0-alpha.44",
"resolved": "https://registry.npmjs.org/@vuelidate/core/-/core-2.0.0-alpha.44.tgz",
"integrity": "sha512-3DlCe3E0RRXbB+OfPacUetKhLmXzmnjeHkzjnbkc03p06mKm6h9pXR5pd6Mv4s4tus4sieuKDb2YWNmKK6rQeA==",
"dev": true,
"dependencies": {
"vue-demi": "^0.13.4"
}
},
"node_modules/@vuelidate/core/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"dev": true,
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vuelidate/validators": {
"version": "2.0.0-alpha.31",
"resolved": "https://registry.npmjs.org/@vuelidate/validators/-/validators-2.0.0-alpha.31.tgz",
"integrity": "sha512-+MFA9nZ7Y9zCpq383/voPDk/hiAmu6KqiJJhLOYB/FmrUPVoyKnuKnI9Bwiq8ok9GZlVkI8BnIrKPKGj9QpwiQ==",
"dev": true,
"dependencies": {
"vue-demi": "^0.13.4"
}
},
"node_modules/@vuelidate/validators/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"dev": true,
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/head": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@vueuse/head/-/head-0.7.9.tgz",
@ -9955,6 +10027,42 @@
"integrity": "sha512-dTyhTIRmGXBjxJE+skC8tTWCGLCVc4wQgRRLt8+O9p5ewBAjoBwtCAkLPrtToSr1xltoe3st21Pv953aOZ7alg==",
"dev": true
},
"@vuelidate/core": {
"version": "2.0.0-alpha.44",
"resolved": "https://registry.npmjs.org/@vuelidate/core/-/core-2.0.0-alpha.44.tgz",
"integrity": "sha512-3DlCe3E0RRXbB+OfPacUetKhLmXzmnjeHkzjnbkc03p06mKm6h9pXR5pd6Mv4s4tus4sieuKDb2YWNmKK6rQeA==",
"dev": true,
"requires": {
"vue-demi": "^0.13.4"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"dev": true,
"requires": {}
}
}
},
"@vuelidate/validators": {
"version": "2.0.0-alpha.31",
"resolved": "https://registry.npmjs.org/@vuelidate/validators/-/validators-2.0.0-alpha.31.tgz",
"integrity": "sha512-+MFA9nZ7Y9zCpq383/voPDk/hiAmu6KqiJJhLOYB/FmrUPVoyKnuKnI9Bwiq8ok9GZlVkI8BnIrKPKGj9QpwiQ==",
"dev": true,
"requires": {
"vue-demi": "^0.13.4"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"dev": true,
"requires": {}
}
}
},
"@vueuse/head": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@vueuse/head/-/head-0.7.9.tgz",

View File

@ -20,6 +20,8 @@
"primeicons": "^5.0.0",
"prismjs": "^1.29.0",
"sass": "^1.45.0",
"sass-loader": "^8.0.2"
"sass-loader": "^8.0.2",
"@vuelidate/core": "^2.0.0-alpha.14",
"@vuelidate/validators": "^2.0.0-alpha.12"
}
}

View File

@ -0,0 +1,255 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Accessibility</h1>
<p>An introduction to accessibility and how it translates to Vue UI Components.</p>
</div>
</div>
<div class="content-section documentation">
<p class="line-height-3 bg-indigo-600 text-white p-3 text-lg" style="border-radius: 10px">
Accessibility is a major concern of the Prime UI libraries and PrimeVue is no exception. <a href="https://www.primetek.com.tr" class="text-white">PrimeTek</a> teams have initiated a significant process to review and enhance the
accessibility features of the components. This guide documents the foundation of the general guidelines that PrimeVue will follow and each component documentation will have a separate <b>Accessibility</b> section that states the
keyboard support, screen reader compatibility, the implementation details along with tips to achieve WCAG compliancy. This work has been initiated in Q2 2022 and planned to be completed by early Q3. PrimeVue will be the reference
implementation which then will be ported to PrimeFaces, PrimeNG and PrimeReact.
</p>
<h3>Introduction</h3>
<p>
According to the World Health Organization, 15% of the world population has a disability to some degree. As a result, accessibility features in any context such as a ramp for wheelchair users or a multimedia with captions are crucial
to ensure content can be consumed by anyone.
</p>
<h5>Disabilities</h5>
<p>Types of disabilities are diverse so you need to know your audience well and how they interact with the content created. There four main categories;</p>
<h6>Visual Impairments</h6>
<p>
Blindness, low-level vision or color blindness are the common types of visual impairments. Screen magnifiers and the color blind mode are usually built-in features of the browsers whereas for people who rely on screen readers, page
developers are required to make sure content is readable by the readers. Popular readers are <a href="https://www.nvaccess.org" alt="NVDA Reader">NVDA</a>,
<a href="https://www.freedomscientific.com/Products/software/JAWS/" alt="JAWS Reader">JAWS</a> and <a href="https://www.chromevox.com" alt="ChromeVox Reader">ChromeVox</a>.
</p>
<h6>Hearing Impairments</h6>
<p>
Deafness or hearing loss refers to the inability to hear sounds totally or partially. People with hearing impairments use assistive devices however it may not be enough when interacting with a web page. Common implementation is
providing textual alternatives, transcripts and captions for content with audio.
</p>
<h6>Mobility Impairments</h6>
<p>
People with mobility impairments have disabilities related to movement due to loss of a limb, paralysis or other varying reasons. Assistive technologies like a head pointer is a device to interact with a screen whereas keyboard or a
trackpad remain as solutions for people who are not able to utilize a mouse.
</p>
<h6>Cognitive Impairments</h6>
<p>
Cognitive impairments have a wider range that includes people with learning disabilities, depression and dyslexia. A well designed content also leads to better user experience for people without disabilities so designing for cognitive
impairments result in better design for any user.
</p>
<h3>Web Content</h3>
<p>
Correct page structure with the aid of assistive technologies are the core ingridients for an accessible web content. HTML is based on an accessible foundation, form controls can be used by keyboard by default and semantic HTML is
easier to be processed by a screen reader.
</p>
<h5>WCAG</h5>
<p>
<a href="https://www.w3.org/WAI/standards-guidelines/wcag/" alt="WCAG Website">WCAG</a> refers to <strong>Web Content Accessibility Guideline</strong>, a standard managed by the WAI (Web Accessibility Initiative) of W3C (World Wide
Web Consortium). WCAG consists of recommendations for making the web content more accessible. PrimeVue components aim high level of WCAG compliancy in the near future.
</p>
<p>
Various countries around the globe have governmental policies regarding web accessibility as well. Most well known of these are <a href="https://www.section508.gov/manage/laws-and-policies/">Section 508</a> in the US and
<a href="https://digital-strategy.ec.europa.eu/en/policies/web-accessibility">Web Accessibility Directive</a> of the European Union.
</p>
<h5>Form Controls</h5>
<p>
Native form elements should be preferred instead of elements that are meant for other purposes like presentation. As an example, button below is rendered as a form control by the browser, can receive focus via tabbing and can be used
with space key as well to trigger.
</p>
<pre v-code.script><code>
&lt;button @click="onButtonClick(event)"&gt;Click&lt;/button&gt;
</code></pre>
<p>On the other hand, a fancy css based button using a div has no keyboard or screen reader support.</p>
<pre v-code.script><code>
&lt;button class="fancy-button" @click="onButtonClick(event)"&gt;Click&lt;/button&gt;
</code></pre>
<p>
<i>tabindex</i> is required to make a div element accessible in addition to use a keydown to bring the keyboard support back. To avoid the overload and implementing functionality that is already provided by the browser, native form
controls should be preferred.
</p>
<pre v-code.script><code>
&lt;div class="fancy-button" @click="onClick(event)" @keydown="onKeyDown(event)" tabindex="0"&gt;Click&lt;/div&gt;
</code></pre>
<h5>Relations</h5>
<p>Form components must be related to another element that describes what the form element is used for. This is usually achieved with the <i>label</i> element.</p>
<pre v-code.script><code>
&lt;label for="myinput"&gt;Username:&lt;/label&gt;
&lt;input id="myinput" type="text" name="username" /&gt;
</code></pre>
<h5>Semantic HTML</h5>
<p>
HTML offers various element to organize content on a web page that screen readers are aware of. Preferring Semantic HTML for good semantics provide out of the box support for reader which is not possible when regular
<i>div</i> elements with classes are used. Consider the following example that do not mean too much for readers.
</p>
<pre v-code.script><code>
&lt;div class="header"&gt;
&lt;div class="header-text"&gt;Header&lt;/div&gt;
&lt;/div&gt;
&lt;div class="nav"&gt;&lt;/div&gt;
&lt;div class="main"&gt;
&lt;div class="content"&gt;
&lt;/div&gt;
&lt;div class="sidebar"&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="footer"&gt;
&lt;/div&gt;
</code></pre>
<p>Same layout can be achieved using the semantic elements with screen reader support built-in.</p>
<pre v-code.script><code>
&lt;header&gt;
&lt;h1&gt;Header&lt;/h1&gt;
&lt;/header&gt;
&lt;nav&gt;&lt;/nav&gt;
&lt;main&gt;
&lt;article&gt;&lt;/article&gt;
&lt;aside&gt;&lt;/aside&gt;
&lt;/main&gt;
&lt;footer&gt;
&lt;/footer&gt;
</code></pre>
<h5>WAI-ARIA</h5>
<p>
ARIA refers to "Accessible Rich Internet Applications" is a suite to fill the gap where semantic HTML is inadequate. These cases are mainly related to rich UI components/widgets. Although browser support for rich UI components such as
a datepicker or colorpicker has been improved over the past years many web developers still utilize UI components derived from standard HTML elements created by them or by other projects like PrimeVue. These types of components must
provide keyboard and screen reader support, the latter case is where the WAI-ARIA is utilized.
</p>
<p>
ARIA consists of roles, properties and attributes. <b>Roles</b> define what the element is mainly used for e.g. <i>checkbox</i>, <i>dialog</i>, <i>tablist</i> whereas <b>States</b> and <b>Properties</b> define the metadata of the
element like <i>aria-checked</i>, <i>aria-disabled</i>.
</p>
<p>Consider the following case of a native checkbox. It has built-in keyboard and screen reader support.</p>
<pre v-code.script><code>
&lt;input type="checkbox" value="Prime" name="ui" checked&gt;
</code></pre>
<p>
A fancy checkbox with css animations might look more appealing but accessibility might be lacking. Checkbox below may display a checked font icon with animations however it is not tabbable, cannot be checked with space key and cannot
be read by a reader.
</p>
<pre v-code.script><code>
&lt;div class="fancy-checkbox"&gt;
&lt;i class="checked-icon" v-if="checked"&gt;&lt;/i&gt;
&lt;/div&gt;
</code></pre>
<p>One alternative is using ARIA roles for readers and use javascript for keyboard support. Notice the usage of <i>aria-labelledby</i> as a replacement of the <i>label</i> tag with for.</p>
<pre v-code.script><code>
&lt;span id="chk-label"&gt;Remember Me&lt;/span&gt;
&lt;div class="fancy-checkbox" role="checkbox" aria-checked="false" tabindex="0" aria-labelledby="chk-label"
@click="toggle" @keydown="onKeyDown(event)"&gt;
&lt;i class="checked-icon" v-if="checked"&gt;&lt;/i&gt;
&lt;/div&gt;
</code></pre>
<p>
However the best practice is combining semantic HTML for accessibility while keeping the design for UX. This approach involves hiding a native checkbox for accessibility and using javascript events to update its state. Notice the
usage of <i>p-sr-only</i>
that hides the elements from the user but not from the screen reader.
</p>
<pre v-code.script><code>
&lt;label for="chkbox"&gt;Remember Me&lt;/label&gt;
&lt;div class="fancy-checkbox" @click="toggle"&gt;
&lt;input class="p-sr-only" type="checkbox" id="chkbox" @focus="updateParentVisuals" @blur="updateParentVisuals"
@keydown="onKeyDown(event)"&gt;
&lt;i class="checked-icon" v-if="checked"&gt;&lt;/i&gt;
&lt;/div&gt;
</code></pre>
<p>A working sample is the PrimeVue checkbox that is tabbable, keyboard accessible and is compliant with a screen reader. Instead of ARIA roles it relies on a hidden native checkbox.</p>
<div class="flex align-items-center">
<label for="binary" class="mr-2">Remember Me</label>
<Checkbox id="binary" binary v-model="checked" />
</div>
<h5>Colors</h5>
<p>Colors on a web page should aim a contrast ratio of at least <strong>4.5:1</strong> and consider a selection of colors that do not cause vibration.</p>
<h6>Good Contrast</h6>
<p>Color contrast between the background and the foreground content should be sufficient enough to ensure readability. Example below displays two cases with good and bad samples.</p>
<div class="flex">
<div class="h-8rem w-8rem flex justify-content-center align-items-center mr-5 font-bold bg-blue-600" style="border-radius: 10px">
<span class="text-white">GOOD</span>
</div>
<div class="h-8rem w-8rem flex justify-content-center align-items-center mr-5 font-bold bg-blue-400" style="border-radius: 10px">
<span class="text-white">BAD</span>
</div>
</div>
<h6>Vibration</h6>
<p>Color vibration is leads to an illusion of motion due to choosing colors that have low visibility against each other. Color combinations need to be picked with caution to avoid vibration.</p>
<div class="flex">
<div class="h-8rem w-8rem flex justify-content-center align-items-center mr-5 font-bold bg-pink-500" style="border-radius: 10px">
<span class="text-blue-500">VIBRATE</span>
</div>
</div>
<h6>Dark Mode</h6>
<p>Highly saturated colors should be avoided when used within a dark design scheme as they cause eye strain. Instead desaturated colors should be preferred.</p>
<div class="flex">
<div class="h-8rem w-8rem flex flex-column justify-content-center align-items-center mr-5 font-bold bg-gray-900" style="border-radius: 10px">
<span class="text-indigo-500">Indigo 500</span>
<i class="text-indigo-500 pi pi-times-circle mt-3 text-xl"></i>
</div>
<div class="h-8rem w-8rem flex flex-column justify-content-center align-items-center mr-5 font-bold bg-gray-900" style="border-radius: 10px">
<span class="text-indigo-200">Indigo 200</span>
<i class="text-indigo-200 pi pi-check-circle mt-3 text-xl"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
checked: false
};
}
};
</script>

886
pages/accordion/AccordionDoc.vue Executable file
View File

@ -0,0 +1,886 @@
<template>
<AppDoc name="AccordionDemo" :sources="sources" github="accordion/AccordionDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Accordion from 'primevue/accordion';
import AccordionTab from 'primevue/accordiontab';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/accordion/accordion.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/accordiontab/accordiontab.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Accordion element consists of one or more AccordionTab elements. Title of the tab is defined using header attribute.</p>
<pre v-code><code>
&lt;Accordion&gt;
&lt;AccordionTab header="Header I"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header II"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header III"&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<h5>Active</h5>
<p>Visibility of the content is specified with the <i>activeIndex</i> property that supports one or two-way binding.</p>
<pre v-code><code>
&lt;Accordion :activeIndex="0"&gt;
&lt;AccordionTab header="Header I"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header II"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header III"&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<p>Two-way binding requires v-model.</p>
<pre v-code><code>
&lt;Accordion v-model:activeIndex="activeIndex"&gt;
&lt;AccordionTab header="Header I"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header II"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header III"&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<h5>Multiple</h5>
<p>By default only one tab at a time can be active, enabling multiple property changes this behavior to allow multiple tabs be active at the same time.</p>
<pre v-code><code>
&lt;Accordion :multiple="true"&gt;
&lt;AccordionTab header="Header I"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header II"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header III"&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<h5>Disabled</h5>
<p>A tab can be disabled by setting the <i>disabled</i> property to true.</p>
<pre v-code><code>
&lt;Accordion&gt;
&lt;AccordionTab header="Header I"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header II"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header III" :disabled="true"&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<h5>Custom Content at Headers</h5>
<p>Custom content for the title section of a panel is defined using the header template.</p>
<pre v-code><code>
&lt;Accordion&gt;
&lt;AccordionTab&gt;
&lt;template #header&gt;
&lt;i class="pi pi-calendar"&gt;&lt;/i&gt;
&lt;span&gt;Header I&lt;/span&gt;
&lt;/template&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab&gt;
&lt;template #header&gt;
&lt;i class="pi pi-calendar"&gt;&lt;/i&gt;
&lt;span&gt;Header II&lt;/span&gt;
&lt;/template&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab&gt;
&lt;template #header&gt;
&lt;i class="pi pi-calendar"&gt;&lt;/i&gt;
&lt;span&gt;Header III&lt;/span&gt;
&lt;/template&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<h5>Programmatic Control</h5>
<p>Tabs can be controlled programmatically using <i>activeIndex</i> property.</p>
<pre v-code><code>
&lt;Button @click="active = 0" class="p-button-text" label="Activate 1st" /&gt;
&lt;Button @click="active = 1" class="p-button-text" label="Activate 2nd" /&gt;
&lt;Button @click="active = 2" class="p-button-text" label="Activate 3rd" /&gt;
&lt;Accordion :multiple="true" :activeIdex="active"&gt;
&lt;AccordionTab header="Header I"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header II"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header III"&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
active: 0
}
}
}
</code></pre>
<h5>Dynamic Tabs</h5>
<p>Tabs can be generated dynamically using the standard <i>v-for</i> directive.</p>
<pre v-code><code><template v-pre>
&lt;Accordion&gt;
&lt;AccordionTab v-for="tab in tabs" :key="tab.title" :header="tab.title"&gt;
&lt;p&gt;{{tab.content}}&lt;/p&gt;
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</template>
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
tabs: [
{title: 'Title 1', content: 'Content 1'},
{title: 'Title 3', content: 'Content 2'},
{title: 'Title 3', content: 'Content 3'}
]
}
}
}
</code></pre>
<h5>Lazy Rendering</h5>
<p>
All tabs are rendered when mounted and inactive tabs are hidden with CSS. Enabling <i>lazy</i> option activates the dynamic mode where a tab is only rendered at DOM when it is active. This option is useful to speed up the initial
rendering performance if there are many tabs.
</p>
<pre v-code><code>
&lt;Accordion lazy&gt;
&lt;AccordionTab header="Header I"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header II"&gt;
Content
&lt;/AccordionTab&gt;
&lt;AccordionTab header="Header III"&gt;
Content
&lt;/AccordionTab&gt;
&lt;/Accordion&gt;
</code></pre>
<h5>Properties of AccordionTab</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>header</td>
<td>string</td>
<td>null</td>
<td>Orientation of tab headers.</td>
</tr>
<tr>
<td>headerStyle</td>
<td>string</td>
<td>null</td>
<td>Inline style of the tab header.</td>
</tr>
<tr>
<td>headerClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the tab header.</td>
</tr>
<tr>
<td>headerProps</td>
<td>object</td>
<td>null</td>
<td>Uses to pass all properties of the HTMLDivElement to the tab header.</td>
</tr>
<tr>
<td>headerActionProps</td>
<td>object</td>
<td>null</td>
<td>Uses to pass all properties of the HTMLAnchorElement to the focusable anchor element inside the tab header.</td>
</tr>
<tr>
<td>contentStyle</td>
<td>string</td>
<td>null</td>
<td>Inline style of the tab content.</td>
</tr>
<tr>
<td>contentClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the tab content.</td>
</tr>
<tr>
<td>contentProps</td>
<td>object</td>
<td>null</td>
<td>Uses to pass all properties of the HTMLDivElement to the tab content.</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>false</td>
<td>Whether the tab is disabled.</td>
</tr>
</tbody>
</table>
</div>
<h5>Properties of Accordion</h5>
<p>Any property as style and class are passed to the main container element. Following is the additional property to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>multiple</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, multiple tabs can be activated at the same time.</td>
</tr>
<tr>
<td>activeIndex</td>
<td>number|array</td>
<td>null</td>
<td>Index of the active tab or an array of indexes in multiple mode.</td>
</tr>
<tr>
<td>lazy</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, hidden tabs are not rendered at all. Defaults to false that hides tabs with css.</td>
</tr>
<tr>
<td>expandIcon</td>
<td>string</td>
<td>pi-chevron-right</td>
<td>Icon of a collapsed tab.</td>
</tr>
<tr>
<td>collapseIcon</td>
<td>string</td>
<td>pi-chevron-down</td>
<td>Icon of an expanded tab.</td>
</tr>
<tr>
<td>tabindex</td>
<td>number</td>
<td>0</td>
<td>Index of the element in tabbing order.</td>
</tr>
<tr>
<td>selectOnFocus</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, the focused tab is activated.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>tab-open</td>
<td>
event.originalEvent: Browser event <br />
event.index: Opened tab index
</td>
<td>Callback to invoke when a tab gets expanded.</td>
</tr>
<tr>
<td>tab-close</td>
<td>
event.originalEvent: Browser event <br />
event.index: Closed tab index
</td>
<td>Callback to invoke when an active tab is collapsed by clicking on the header.</td>
</tr>
<tr>
<td>tab-click</td>
<td>
event.originalEvent: Browser event <br />
event.index: Index of the clicked tab
</td>
<td>Callback to invoke when an active tab is clicked.</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-accordion</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-accordion-header</td>
<td>Header of a tab.</td>
</tr>
<tr>
<td>p-accordion-content</td>
<td>Container of a tab.</td>
</tr>
</tbody>
</table>
</div>
<h5>Accessibility</h5>
<h6>Screen Reader</h6>
<p>
Accordion header elements have a <i>button</i> role and use <i>aria-controls</i> to define the id of the content section along with <i>aria-expanded</i> for the visibility state. The value to read a header element defaults to the value of
the <i>header</i> property and can be customized by defining an <i>aria-label</i> or <i>aria-labelledby</i> via the <i>headerActionProps</i> property.
</p>
<p>The content uses <i>region</i> role, defines an id that matches the <i>aria-controls</i> of the header and <i>aria-labelledby</i> referring to the id of the header.</p>
<h6>Header Keyboard Support</h6>
<div className="doc-tablewrapper">
<table className="doc-table">
<thead>
<tr>
<th>Key</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<i>tab</i>
</td>
<td>Moves focus to the next the focusable element in the page tab sequence.</td>
</tr>
<tr>
<td><i>shift</i> + <i>tab</i></td>
<td>Moves focus to the previous the focusable element in the page tab sequence.</td>
</tr>
<tr>
<td>
<i>enter</i>
</td>
<td>Toggles the visibility of the content.</td>
</tr>
<tr>
<td>
<i>space</i>
</td>
<td>Toggles the visibility of the content.</td>
</tr>
<tr>
<td>
<i>down arrow</i>
</td>
<td>Moves focus to the next header. If focus is on the last header, moves focus to the first header.</td>
</tr>
<tr>
<td>
<i>up arrow</i>
</td>
<td>Moves focus to the previous header. If focus is on the first header, moves focus to the last header.</td>
</tr>
<tr>
<td>
<i>home</i>
</td>
<td>Moves focus to the first header.</td>
</tr>
<tr>
<td>
<i>end</i>
</td>
<td>Moves focus to the last header.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<h5>Default</h5>
<Accordion :activeIndex="0">
<AccordionTab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
</Accordion>
<h5>Multiple</h5>
<Accordion :multiple="true" :activeIndex="[0]">
<AccordionTab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
<AccordionTab header="Header IV" :disabled="true">
<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
</Accordion>
<h5>Programmatic</h5>
<div class="pb-3">
<Button @click="active = 0" class="p-button-text" label="Activate 1st" />
<Button @click="active = 1" class="p-button-text mr-2" label="Activate 2nd" />
<Button @click="active = 2" class="p-button-text mr-2" label="Activate 3rd" />
</div>
<Accordion v-model:activeIndex="active">
<AccordionTab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quas architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ration voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
</Accordion>
<h5>Custom Headers</h5>
<Accordion class="accordion-custom" :activeIndex="0">
<AccordionTab>
<template #header>
<i class="pi pi-calendar"></i>
<span>Header I</span>
</template>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab>
<template #header>
<i class="pi pi-user"></i>
<span>Header II</span>
</template>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab>
<template #header>
<i class="pi pi-search"></i>
<span>Header III</span>
<i class="pi pi-cog"></i>
</template>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
</Accordion>
<h5>Dynamic Tabs</h5>
<Accordion>
<AccordionTab v-for="tab in tabs" :key="tab.title" :header="tab.title">
<p>{{tab.content}}</p>
</AccordionTab>
</Accordion>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
tabs: [
{
title: "Header I",
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
title: "Header II",
content: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi."
},
{
title: "Header III",
content: "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus."
}
]
}
}
}
<\\/script>
<style lang="scss" scoped>
.accordion-custom {
i, span {
vertical-align: middle;
}
span {
margin: 0 .5rem;
}
}
.p-accordion p {
line-height: 1.5;
margin: 0;
}
</style>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<h5>Default</h5>
<Accordion :activeIndex="0">
<AccordionTab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
</Accordion>
<h5>Multiple</h5>
<Accordion :multiple="true" :activeIndex="[0]">
<AccordionTab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
<AccordionTab header="Header IV" :disabled="true">
<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
</Accordion>
<h5>Programmatic</h5>
<div class="pb-3">
<Button @click="active = 0" class="p-button-text" label="Activate 1st" />
<Button @click="active = 1" class="p-button-text mr-2" label="Activate 2nd" />
<Button @click="active = 2" class="p-button-text mr-2" label="Activate 3rd" />
</div>
<Accordion v-model:activeIndex="active">
<AccordionTab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quas architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ration voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
</Accordion>
<h5>Custom Headers</h5>
<Accordion class="accordion-custom" :activeIndex="0">
<AccordionTab>
<template #header>
<i class="pi pi-calendar"></i>
<span>Header I</span>
</template>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</AccordionTab>
<AccordionTab>
<template #header>
<i class="pi pi-user"></i>
<span>Header II</span>
</template>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</AccordionTab>
<AccordionTab>
<template #header>
<i class="pi pi-search"></i>
<span>Header III</span>
<i class="pi pi-cog"></i>
</template>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</AccordionTab>
</Accordion>
<h5>Dynamic Tabs</h5>
<Accordion>
<AccordionTab v-for="tab in tabs" :key="tab.title" :header="tab.title">
<p>{{tab.content}}</p>
</AccordionTab>
</Accordion>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const active = ref(0);
const tabs = ref([
{
title: "Header I",
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
title: "Header II",
content: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi."
},
{
title: "Header III",
content: "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus."
}
]);
return { active, tabs }
}
}
<\\/script>
<style lang="scss" scoped>
.accordion-custom {
i, span {
vertical-align: middle;
}
span {
margin: 0 .5rem;
}
}
.p-accordion p {
line-height: 1.5;
margin: 0;
}
</style>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/accordion/accordion.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/accordiontab/accordiontab.min.js"><\\/script>`,
content: `<div id="app">
<h5>Default</h5>
<p-accordion :active-index="0">
<p-accordiontab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p-accordiontab>
<p-accordiontab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</p-accordiontab>
<p-accordiontab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</p-accordiontab>
</p-accordion>
<h5>Multiple</h5>
<p-accordion :multiple="true" :active-index="[0]">
<p-accordiontab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p-accordiontab>
<p-accordiontab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</p-accordiontab>
<p-accordiontab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</p-accordiontab>
<p-accordiontab header="Header IV" :disabled="true">
<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p-accordiontab>
</p-accordion>
<h5>Programmatic</h5>
<div class="pb-3">
<p-button @click="active = 0" class="p-button-text" label="Activate 1st"></p-button>
<p-button @click="active = 1" class="p-button-text mr-2" label="Activate 2nd"></p-button>
<p-button @click="active = 2" class="p-button-text mr-2" label="Activate 3rd"></p-button>
</div>
<p-accordion v-model:active-index="active">
<p-accordiontab header="Header I">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p-accordiontab>
<p-accordiontab header="Header II">
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quas architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ration voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</p-accordiontab>
<p-accordiontab header="Header III">
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</p-accordiontab>
</p-accordion>
<h5>Custom Headers</h5>
<p-accordion class="accordion-custom" :active-index="0">
<p-accordiontab>
<template #header>
<i class="pi pi-calendar"></i>
<span>Header I</span>
</template>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</p-accordiontab>
<p-accordiontab>
<template #header>
<i class="pi pi-user"></i>
<span>Header II</span>
</template>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
</p-accordiontab>
<p-accordiontab>
<template #header>
<i class="pi pi-search"></i>
<span>Header III</span>
<i class="pi pi-cog"></i>
</template>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</p-accordiontab>
</p-accordion>
<h5>Dynamic Tabs</h5>
<p-accordion>
<p-accordiontab v-for="tab in tabs" :key="tab.title" :header="tab.title">
<p>{{tab.content}}</p>
</p-accordiontab>
</p-accordion>
</div>
<script type="module">
const { createApp, ref } = Vue;
const App = {
setup() {
const active = ref(0);
const tabs = ref([
{
title: "Header I",
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
},
{
title: "Header II",
content: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi."
},
{
title: "Header III",
content: "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus."
}
]);
return { active, tabs }
},
components: {
"p-accordion": primevue.accordion,
"p-accordiontab": primevue.accordiontab,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.accordion-custom i{
vertical-align: middle;
}
.accordion-custom span {
vertical-align: middle;
margin: 0 .5rem;
}
.p-accordion p {
line-height: 1.5;
margin: 0;
}
</style>
`
}
}
};
}
};
</script>

189
pages/accordion/index.vue Executable file
View File

@ -0,0 +1,189 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Accordion</h1>
<p>Accordion groups a collection of contents in tabs.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Default</h5>
<Accordion :activeIndex="0">
<AccordionTab header="Header I">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo
enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in
culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</AccordionTab>
</Accordion>
<h5>Multiple</h5>
<Accordion :multiple="true" :activeIndex="[0]">
<AccordionTab header="Header I">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo
enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in
culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</AccordionTab>
<AccordionTab header="Header IV" :disabled="true"> </AccordionTab>
</Accordion>
<h5>Programmatic</h5>
<div class="pb-3">
<Button @click="active = 0" class="p-button-text" label="Activate 1st" />
<Button @click="active = 1" class="p-button-text mr-2" label="Activate 2nd" />
<Button @click="active = 2" class="p-button-text mr-2" label="Activate 3rd" />
</div>
<Accordion v-model:activeIndex="active">
<AccordionTab header="Header I">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
</p>
</AccordionTab>
<AccordionTab header="Header II">
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo
enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</AccordionTab>
<AccordionTab header="Header III">
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in
culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</AccordionTab>
</Accordion>
<h5>Custom Headers</h5>
<Accordion class="accordion-custom" :activeIndex="0">
<AccordionTab>
<template #header>
<i class="pi pi-calendar"></i>
<span>Header I</span>
</template>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
</p>
</AccordionTab>
<AccordionTab>
<template #header>
<i class="pi pi-user"></i>
<span>Header II</span>
</template>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo
enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
</AccordionTab>
<AccordionTab>
<template #header>
<i class="pi pi-search"></i>
<span>Header III</span>
<i class="pi pi-cog"></i>
</template>
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in
culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</AccordionTab>
</Accordion>
<h5>Dynamic Tabs</h5>
<Accordion>
<AccordionTab v-for="tab in tabs" :key="tab.title" :header="tab.title">
<p>{{ tab.content }}</p>
</AccordionTab>
</Accordion>
</div>
</div>
<AccordionDoc />
</div>
</template>
<script>
import AccordionDoc from './AccordionDoc';
export default {
data() {
return {
active: 0,
tabs: [
{
title: 'Header I',
content: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`
},
{
title: 'Header II',
content: `Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.`
},
{
title: 'Header III',
content: `At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.`
}
]
};
},
components: {
AccordionDoc: AccordionDoc
}
};
</script>
<style lang="scss" scoped>
.accordion-custom {
i,
span {
vertical-align: middle;
}
span {
margin: 0 0.5rem;
}
}
.p-accordion p {
line-height: 1.5;
margin: 0;
}
</style>

File diff suppressed because it is too large Load Diff

153
pages/autocomplete/index.vue Executable file
View File

@ -0,0 +1,153 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>AutoComplete</h1>
<p>AutoComplete is an input component that provides real-time suggestions when being typed.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<AutoComplete v-model="selectedCountry1" :suggestions="filteredCountries" @complete="searchCountry($event)" optionLabel="name" />
<h5>Grouped</h5>
<AutoComplete v-model="selectedCity" :suggestions="filteredCities" @complete="searchCity($event)" optionLabel="label" optionGroupLabel="label" optionGroupChildren="items">
<template #optiongroup="slotProps">
<div class="flex align-items-center country-item">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.item.code.toLowerCase()" width="18" />
<div>{{ slotProps.item.label }}</div>
</div>
</template>
</AutoComplete>
<h5>Dropdown, Templating and Force Selection</h5>
<AutoComplete v-model="selectedCountry2" loadingIcon="pi pi-spinner" :suggestions="filteredCountries" @complete="searchCountry($event)" :dropdown="true" optionLabel="name" forceSelection>
<template #item="slotProps">
<div class="country-item">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.item.code.toLowerCase()" />
<div>{{ slotProps.item.name }}</div>
</div>
</template>
</AutoComplete>
<h5>Virtual Scroll (1000 Items)</h5>
<AutoComplete v-model="selectedItem" :suggestions="filteredItems" @complete="searchItems" :virtualScrollerOptions="{ itemSize: 38 }" optionLabel="label" dropdown />
<h5>Multiple</h5>
<span class="p-fluid">
<AutoComplete :multiple="true" v-model="selectedCountries" :suggestions="filteredCountries" @complete="searchCountry($event)" optionLabel="name" />
</span>
</div>
</div>
<AutoCompleteDoc />
</div>
</template>
<script>
import CountryService from '../../service/CountryService';
import AutoCompleteDoc from './AutoCompleteDoc';
import { FilterService, FilterMatchMode } from 'primevue/api';
export default {
data() {
return {
countries: null,
selectedCountry1: null,
selectedCountry2: null,
selectedCity: null,
filteredCities: null,
filteredCountries: null,
selectedCountries: [],
selectedItem: null,
filteredItems: null,
groupedCities: [
{
label: 'Germany',
code: 'DE',
items: [
{ label: 'Berlin', value: 'Berlin' },
{ label: 'Frankfurt', value: 'Frankfurt' },
{ label: 'Hamburg', value: 'Hamburg' },
{ label: 'Munich', value: 'Munich' }
]
},
{
label: 'USA',
code: 'US',
items: [
{ label: 'Chicago', value: 'Chicago' },
{ label: 'Los Angeles', value: 'Los Angeles' },
{ label: 'New York', value: 'New York' },
{ label: 'San Francisco', value: 'San Francisco' }
]
},
{
label: 'Japan',
code: 'JP',
items: [
{ label: 'Kyoto', value: 'Kyoto' },
{ label: 'Osaka', value: 'Osaka' },
{ label: 'Tokyo', value: 'Tokyo' },
{ label: 'Yokohama', value: 'Yokohama' }
]
}
],
items: Array.from({ length: 1000 }, (_, i) => ({ label: `Item #${i}`, value: i }))
};
},
countryService: null,
created() {
this.countryService = new CountryService();
},
mounted() {
this.countryService.getCountries().then((data) => (this.countries = data));
},
methods: {
searchCountry(event) {
setTimeout(() => {
if (!event.query.trim().length) {
this.filteredCountries = [...this.countries];
} else {
this.filteredCountries = this.countries.filter((country) => {
return country.name.toLowerCase().startsWith(event.query.toLowerCase());
});
}
}, 250);
},
searchCity(event) {
let query = event.query;
let filteredCities = [];
for (let country of this.groupedCities) {
let filteredItems = FilterService.filter(country.items, ['label'], query, FilterMatchMode.CONTAINS);
if (filteredItems && filteredItems.length) {
filteredCities.push({ ...country, ...{ items: filteredItems } });
}
}
this.filteredCities = filteredCities;
},
searchItems(event) {
//in a real application, make a request to a remote url with the query and return filtered results, for demo we filter at client side
let query = event.query;
let filteredItems = [];
for (let i = 0; i < this.items.length; i++) {
let item = this.items[i];
if (item.label.toLowerCase().indexOf(query.toLowerCase()) === 0) {
filteredItems.push(item);
}
}
this.filteredItems = filteredItems;
}
},
components: {
AutoCompleteDoc: AutoCompleteDoc
}
};
</script>

517
pages/avatar/AvatarDoc.vue Normal file
View File

@ -0,0 +1,517 @@
<template>
<AppDoc name="AvatarDemo" :sources="sources" github="avatar/AvatarDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Avatar from 'primevue/avatar';
import AvatarGroup from 'primevue/avatargroup';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/avatar/avatar.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/avatargroup/avatargroup.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Avatar has three built-in display modes; "label", "icon" and "image".</p>
<pre v-code><code>
&lt;Avatar label="P" /&gt;
&lt;Avatar icon="pi pi-search" /&gt;
&lt;Avatar image="user.png" /&gt;
</code></pre>
<h5>Sizes</h5>
<p><i>size</i> property defines the size of the Avatar with "large" and "xlarge" as possible values.</p>
<pre v-code><code>
&lt;Avatar label="P" size="large"/&gt;
</code></pre>
<h5>AvatarGroup</h5>
<p>A set of Avatars can be displayed together using the <i>AvatarGroup</i> component.</p>
<pre v-code><code>
&lt;AvatarGroup&gt;
&lt;Avatar label="P" /&gt;
&lt;Avatar icon="pi pi-search" /&gt;
&lt;Avatar image="user.png" /&gt;
&lt;Avatar label="+2" /&gt;
&lt;/AvatarGroup&gt;
</code></pre>
<h5>Shape</h5>
<p>Avatar comes in two different styles specified with the <i>shape</i> property, "square" is the default and "circle" is the alternative.</p>
<pre v-code><code>
&lt;Avatar label="P" shape="circle"/&gt;
</code></pre>
<h5>Badge</h5>
<p>A badge can be added to an Avatar with the <router-link to="/badge">Badge</router-link> directive.</p>
<pre v-code><code>
&lt;Avatar image="user.png" size="xlarge" v-badge.danger="4" /&gt;
</code></pre>
<h5>Templating</h5>
<p>Content can easily be customized with the default slot instead of using the built-in modes.</p>
<pre v-code><code>
&lt;Avatar&gt;
Content
&lt;/Avatar&gt;
</code></pre>
<h5>Properties of Avatar</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>label</td>
<td>string</td>
<td>null</td>
<td>Defines the text to display.</td>
</tr>
<tr>
<td>icon</td>
<td>string</td>
<td>null</td>
<td>Defines the icon to display.</td>
</tr>
<tr>
<td>image</td>
<td>string</td>
<td>null</td>
<td>Defines the image to display.</td>
</tr>
<tr>
<td>size</td>
<td>string</td>
<td>null</td>
<td>Size of the element, valid options are "large" and "xlarge".</td>
</tr>
<tr>
<td>shape</td>
<td>string</td>
<td>square</td>
<td>Shape of the element, valid options are "square" and "circle".</td>
</tr>
</tbody>
</table>
</div>
<h5>Properties of AvatarGroup</h5>
<p>Any property as style and class are passed to the main container element. There are no additional properties.</p>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>error</td>
<td>-</td>
<td>Triggered when an error occurs while loading an image file.</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling of Avatar</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-avatar</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-avatar-image</td>
<td>Container element in image mode.</td>
</tr>
<tr>
<td>p-avatar-circle</td>
<td>Container element with a circle shape.</td>
</tr>
<tr>
<td>p-avatar-text</td>
<td>Text of the Avatar.</td>
</tr>
<tr>
<td>p-avatar-icon</td>
<td>Icon of the Avatar.</td>
</tr>
<tr>
<td>p-avatar-lg</td>
<td>Container element with a large size.</td>
</tr>
<tr>
<td>p-avatar-xl</td>
<td>Container element with an xlarge size.</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling of AvatarGroup</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-avatar-group</td>
<td>Container element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Label</h5>
<Avatar label="P" class="mr-2" size="xlarge" />
<Avatar label="V" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff"/>
<Avatar label="U" class="mr-2" style="background-color:#9c27b0; color: #ffffff" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Circle</h5>
<Avatar label="P" class="mr-2" size="xlarge" shape="circle" />
<Avatar label="V" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff" shape="circle" />
<Avatar label="U" class="mr-2" style="background-color:#9c27b0; color: #ffffff" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Badge</h5>
<Avatar label="U" size="xlarge" style="background-color:#4caf4f; color: #ffffff" v-badge="4" />
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon</h5>
<Avatar icon="pi pi-user" class="mr-2" size="xlarge" />
<Avatar icon="pi pi-user" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff"/>
<Avatar icon="pi pi-user" class="mr-2" style="background-color:#9c27b0; color: #ffffff" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Circle</h5>
<Avatar icon="pi pi-user" class="mr-2" size="xlarge" shape="circle" />
<Avatar icon="pi pi-user" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff" shape="circle" />
<Avatar icon="pi pi-user" class="mr-2" style="background-color:#9c27b0; color: #ffffff" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Badge</h5>
<Avatar icon="pi pi-user" size="xlarge" v-badge="4"/>
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Image</h5>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" size="xlarge" shape="circle" />
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" size="large" shape="circle" />
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Avatar Group</h5>
<AvatarGroup class="mb-3">
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar label="+2" shape="circle" size="large" style="background-color:#9c27b0; color: #ffffff" />
</AvatarGroup>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Image - Badge</h5>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="xlarge" v-badge.danger="4" />
</div>
</div>
</div>
</template>
<script>
export default {
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Label</h5>
<Avatar label="P" class="mr-2" size="xlarge" />
<Avatar label="V" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff"/>
<Avatar label="U" class="mr-2" style="background-color:#9c27b0; color: #ffffff" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Circle</h5>
<Avatar label="P" class="mr-2" size="xlarge" shape="circle" />
<Avatar label="V" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff" shape="circle" />
<Avatar label="U" class="mr-2" style="background-color:#9c27b0; color: #ffffff" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Badge</h5>
<Avatar label="U" size="xlarge" style="background-color:#4caf4f; color: #ffffff" v-badge="4" />
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon</h5>
<Avatar icon="pi pi-user" class="mr-2" size="xlarge" />
<Avatar icon="pi pi-user" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff"/>
<Avatar icon="pi pi-user" class="mr-2" style="background-color:#9c27b0; color: #ffffff" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Circle</h5>
<Avatar icon="pi pi-user" class="mr-2" size="xlarge" shape="circle" />
<Avatar icon="pi pi-user" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff" shape="circle" />
<Avatar icon="pi pi-user" class="mr-2" style="background-color:#9c27b0; color: #ffffff" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Badge</h5>
<Avatar icon="pi pi-user" size="xlarge" v-badge="4"/>
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Image</h5>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" size="xlarge" shape="circle" />
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" size="large" shape="circle" />
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Avatar Group</h5>
<AvatarGroup class="mb-3">
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"/>
<Avatar label="+2" shape="circle" size="large" style="background-color:#9c27b0; color: #ffffff" />
</AvatarGroup>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Image - Badge</h5>
<Avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="xlarge" v-badge.danger="4" />
</div>
</div>
</div>
</template>
<script>
export default {
}
<\\/script>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/avatar/avatar.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/avatargroup/avatargroup.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/badgedirective/badgedirective.min.js"><\\/script>`,
content: `<div id="app">
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Label</h5>
<p-avatar label="P" class="mr-2" size="xlarge"></p-avatar>
<p-avatar label="V" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff"></p-avatar>
<p-avatar label="U" class="mr-2" style="background-color:#9c27b0; color: #ffffff"></p-avatar>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Circle</h5>
<p-avatar label="P" class="mr-2" size="xlarge" shape="circle"></p-avatar>
<p-avatar label="V" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff" shape="circle"></p-avatar>
<p-avatar label="U" class="mr-2" style="background-color:#9c27b0; color: #ffffff" shape="circle"></p-avatar>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Badge</h5>
<p-avatar label="U" size="xlarge" style="background-color:#4caf4f; color: #ffffff" v-badge="4"></p-avatar>
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon</h5>
<p-avatar icon="pi pi-user" class="mr-2" size="xlarge"></p-avatar>
<p-avatar icon="pi pi-user" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff"></p-avatar>
<p-avatar icon="pi pi-user" class="mr-2" style="background-color:#9c27b0; color: #ffffff"></p-avatar>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Circle</h5>
<p-avatar icon="pi pi-user" class="mr-2" size="xlarge" shape="circle"></p-avatar>
<p-avatar icon="pi pi-user" class="mr-2" size="large" style="background-color:#2196F3; color: #ffffff" shape="circle"></p-avatar>
<p-avatar icon="pi pi-user" class="mr-2" style="background-color:#9c27b0; color: #ffffff" shape="circle"></p-avatar>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Badge</h5>
<p-avatar icon="pi pi-user" size="xlarge" v-badge="4"></p-avatar>
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Image</h5>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" size="xlarge" shape="circle"></p-avatar>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" size="large" shape="circle"></p-avatar>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2" shape="circle"></p-avatar>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>p-avatar Group</h5>
<p-avatargroup class="mb-3">
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"></p-avatar>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"></p-avatar>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"></p-avatar>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"></p-avatar>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="large" shape="circle"></p-avatar>
<p-avatar label="+2" shape="circle" size="large" style="background-color:#9c27b0; color: #ffffff"></p-avatar>
</p-avatargroup>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Image - Badge</h5>
<p-avatar image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" size="xlarge" v-badge.danger="4"></p-avatar>
</div>
</div>
</div>
</div>
<script type="module">
const { createApp } = Vue;
const BadgeDirective = primevue.badgedirective;
const App = {
components: {
"p-avatar": primevue.avatar,
"p-avatargroup": primevue.avatargroup
}
};
createApp(App)
.use(primevue.config.default)
.directive("badge", BadgeDirective)
.mount("#app");
<\\/script>`
}
}
};
}
};
</script>

111
pages/avatar/index.vue Normal file
View File

@ -0,0 +1,111 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Avatar</h1>
<p>Avatar represents people using icons, labels and images.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Label</h5>
<Avatar label="P" class="mr-2" size="xlarge" />
<Avatar label="V" class="mr-2" size="large" style="background-color: #2196f3; color: #ffffff" />
<Avatar label="U" class="mr-2" style="background-color: #9c27b0; color: #ffffff" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Circle</h5>
<Avatar label="P" class="mr-2" size="xlarge" shape="circle" />
<Avatar label="V" class="mr-2" size="large" style="background-color: #2196f3; color: #ffffff" shape="circle" />
<Avatar label="U" class="mr-2" style="background-color: #9c27b0; color: #ffffff" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Label - Badge</h5>
<Avatar label="U" size="xlarge" style="background-color: #4caf4f; color: #ffffff" v-badge="4" />
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon</h5>
<Avatar icon="pi pi-user" class="mr-2" size="xlarge" />
<Avatar icon="pi pi-user" class="mr-2" size="large" style="background-color: #2196f3; color: #ffffff" />
<Avatar icon="pi pi-user" class="mr-2" style="background-color: #9c27b0; color: #ffffff" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Circle</h5>
<Avatar icon="pi pi-user" class="mr-2" size="xlarge" shape="circle" />
<Avatar icon="pi pi-user" class="mr-2" size="large" style="background-color: #2196f3; color: #ffffff" shape="circle" />
<Avatar icon="pi pi-user" class="mr-2" style="background-color: #9c27b0; color: #ffffff" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Icon - Badge</h5>
<Avatar icon="pi pi-user" size="xlarge" v-badge="4" />
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="card">
<h5>Image</h5>
<Avatar image="demo/images/avatar/amyelsner.png" class="mr-2" size="xlarge" shape="circle" />
<Avatar image="demo/images/avatar/asiyajavayant.png" class="mr-2" size="large" shape="circle" />
<Avatar image="demo/images/avatar/onyamalimba.png" class="mr-2" shape="circle" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Avatar Group</h5>
<AvatarGroup class="mb-3">
<Avatar image="demo/images/avatar/amyelsner.png" size="large" shape="circle" />
<Avatar image="demo/images/avatar/asiyajavayant.png" size="large" shape="circle" />
<Avatar image="demo/images/avatar/onyamalimba.png" size="large" shape="circle" />
<Avatar image="demo/images/avatar/ionibowcher.png" size="large" shape="circle" />
<Avatar image="demo/images/avatar/xuxuefeng.png" size="large" shape="circle" />
<Avatar label="+2" shape="circle" size="large" style="background-color: #9c27b0; color: #ffffff" />
</AvatarGroup>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Image - Badge</h5>
<Avatar image="demo/images/organization/walter.jpg" size="xlarge" v-badge.danger="4" />
</div>
</div>
</div>
</div>
<AvatarDoc />
</div>
</template>
<script>
import AvatarDoc from './AvatarDoc';
export default {
components: {
AvatarDoc: AvatarDoc
}
};
</script>

316
pages/badge/BadgeDoc.vue Normal file
View File

@ -0,0 +1,316 @@
<template>
<AppDoc name="BadgeDemo" :sources="sources" github="badge/BadgeDemo.vue">
<h5>Getting Started</h5>
<p>Badge can either be used as a standalone component or as a directive.</p>
<h5>Component</h5>
<h6>Import via Module</h6>
<pre v-code.script><code>
import Badge from 'primevue/badge';
</code></pre>
<h6>Import via CDN</h6>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/badge/badge.min.js"&gt;&lt;/script&gt;
</code></pre>
<p>Content of the badge is specified using the <i>value</i> property.</p>
<pre v-code><code>
&lt;Badge value="2"&gt;&lt;/Badge&gt;
</code></pre>
<h5>Directive</h5>
<h6>Import via Module</h6>
<pre v-code.script><code>
import BadgeDirective from 'primevue/badgedirective';
</code></pre>
<h6>Import via CDN</h6>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/badgedirective/badgedirective.min.js"&gt;&lt;/script&gt;
</code></pre>
<p>When used as a directive, badge needs to be configured at the application with a name of your choice.</p>
<pre v-code.script><code>
import BadgeDirective from 'primevue/badgedirective';
app.directive('badge', BadgeDirective);
</code></pre>
<p>Next step is attaching it to an element.</p>
<pre v-code><code>
&lt;i class="pi pi-bell" v-badge="2"&gt;&lt;/i&gt;
</code></pre>
<h5>Severities</h5>
<p>Different color options are available as severity levels. When used as a component use the <i>severity</i> property to apply a severity and use a <i>modifier</i> as the severity value in directive mode.</p>
<ul>
<li>success</li>
<li>info</li>
<li>warning</li>
<li>danger</li>
</ul>
<pre v-code><code>
&lt;Badge value="2" severity="success"&gt;&lt;/Badge&gt;
&lt;i class="pi pi-bell" v-badge.success="2"&gt;&lt;/i&gt;
</code></pre>
<h5>Button Badges</h5>
<p>Buttons provide integrated badge support with the <i>badge</i> and <i>badgeClass</i> properties.</p>
<pre v-code><code>
&lt;Button type="button" label="Emails" badge="8" /&gt;
&lt;Button type="button" label="Messages" icon="pi pi-users" class="p-button-warning" badge="8" badgeClass="p-badge-danger" /&gt;
</code></pre>
<h5>Sizes</h5>
<p>Badge sizes are adjusted with the <i>size</i> property that accepts "large" and "xlarge" as the possible alternatives to the default size. Currently sizes only apply to component mode.</p>
<pre v-code><code>
&lt;Badge value="2"&gt;&lt;/Badge&gt;
&lt;Badge value="4" size="large" severity="warning"&gt;&lt;/Badge&gt;
&lt;Badge value="6" size="xlarge" severity="success"&gt;&lt;/Badge&gt;
</code></pre>
<p>In addition, when placed inside another element, badge sizes can also derive their size from their parent.</p>
<pre v-code><code>
&lt;h1&gt;Heading 1 &lt;Badge value="New"&gt;&lt;/Badge&gt;&lt;/h1&gt;
&lt;h2&gt;Heading 2 &lt;Badge value="New"&gt;&lt;/Badge&gt;&lt;/h2&gt;
</code></pre>
<h5>Templating</h5>
<p>Content can easily be customized with the default slot instead of using the built-in display.</p>
<pre v-code><code>
&lt;Badge&gt;
Content
&lt;/Badge&gt;
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>value</td>
<td>any</td>
<td>null</td>
<td>Value to display inside the badge.</td>
</tr>
<tr>
<td>severity</td>
<td>string</td>
<td>null</td>
<td>Severity type of the badge.</td>
</tr>
<tr>
<td>size</td>
<td>string</td>
<td>null</td>
<td>Size of the badge, valid options are "large" and "xlarge".</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-badge</td>
<td>Badge element</td>
</tr>
<tr>
<td>p-overlay-badge</td>
<td>Wrapper of a badge and its target.</td>
</tr>
<tr>
<td>p-badge-dot</td>
<td>Badge element with no value.</td>
</tr>
<tr>
<td>p-badge-success</td>
<td>Badge element with success severity.</td>
</tr>
<tr>
<td>p-badge-info</td>
<td>Badge element with info severity.</td>
</tr>
<tr>
<td>p-badge-warning</td>
<td>Badge element with warning severity.</td>
</tr>
<tr>
<td>p-badge-danger</td>
<td>Badge element with danger severity.</td>
</tr>
<tr>
<td>p-badge-lg</td>
<td>Large badge element</td>
</tr>
<tr>
<td>p-badge-xl</td>
<td>Extra large badge element</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<h5>Numbers</h5>
<Badge value="2" class="mr-2"></Badge>
<Badge value="8" severity="success" class="mr-2"></Badge>
<Badge value="4" severity="info" class="mr-2"></Badge>
<Badge value="12" severity="warning" class="mr-2"></Badge>
<Badge value="3" severity="danger"></Badge>
<h5 class="mb-4">Positioned Badge</h5>
<i class="pi pi-bell mr-4 p-text-secondary" style="font-size: 2rem" v-badge="2"></i>
<i class="pi pi-calendar mr-4 p-text-secondary" style="font-size: 2rem" v-badge.danger="'10+'"></i>
<i class="pi pi-envelope p-text-secondary" style="font-size: 2rem" v-badge.danger></i>
<h5>Button Badge</h5>
<Button type="button" label="Emails" badge="8" class="mr-2" />
<Button type="button" label="Messages" icon="pi pi-users" class="p-button-warning" badge="8" badgeClass="p-badge-danger" />
<h5>Sizes</h5>
<Badge value="2" class="mr-2"></Badge>
<Badge value="4" class="mr-2" size="large" severity="warning"></Badge>
<Badge value="6" size="xlarge" severity="success"></Badge>
</div>
</template>
<script>
export default {
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<h5>Numbers</h5>
<Badge value="2" class="mr-2"></Badge>
<Badge value="8" severity="success" class="mr-2"></Badge>
<Badge value="4" severity="info" class="mr-2"></Badge>
<Badge value="12" severity="warning" class="mr-2"></Badge>
<Badge value="3" severity="danger"></Badge>
<h5 class="mb-4">Positioned Badge</h5>
<i class="pi pi-bell mr-4 p-text-secondary" style="font-size: 2rem" v-badge="2"></i>
<i class="pi pi-calendar mr-4 p-text-secondary" style="font-size: 2rem" v-badge.danger="'10+'"></i>
<i class="pi pi-envelope p-text-secondary" style="font-size: 2rem" v-badge.danger></i>
<h5>Button Badge</h5>
<Button type="button" label="Emails" badge="8" class="mr-2" />
<Button type="button" label="Messages" icon="pi pi-users" class="p-button-warning" badge="8" badgeClass="p-badge-danger" />
<h5>Sizes</h5>
<Badge value="2" class="mr-2"></Badge>
<Badge value="4" class="mr-2" size="large" severity="warning"></Badge>
<Badge value="6" size="xlarge" severity="success"></Badge>
</div>
</template>
<script>
export default {
}
<\\/script>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/badge/badge.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/badgedirective/badgedirective.min.js"><\\/script>`,
content: `<div id="app">
<h5>Numbers</h5>
<p-badge value="2" class="mr-2"></p-badge>
<p-badge value="8" severity="success" class="mr-2"></p-badge>
<p-badge value="4" severity="info" class="mr-2"></p-badge>
<p-badge value="12" severity="warning" class="mr-2"></p-badge>
<p-badge value="3" severity="danger"></p-badge>
<h5 class="mb-4">Positioned Badge</h5>
<i class="pi pi-bell mr-4 p-text-secondary" style="font-size: 2rem" v-badge="2"></i>
<i class="pi pi-calendar mr-4 p-text-secondary" style="font-size: 2rem" v-badge.danger="'10+'"></i>
<i class="pi pi-envelope p-text-secondary" style="font-size: 2rem" v-badge.danger></i>
<h5>Button Badge</h5>
<p-button type="button" label="Emails" badge="8" class="mr-2"></p-button>
<p-button type="button" label="Messages" icon="pi pi-users" class="p-button-warning" badge="8" badgeClass="p-badge-danger"></p-button>
<h5>Sizes</h5>
<p-badge value="2" class="mr-2"></p-badge>
<p-badge value="4" class="mr-2" size="large" severity="warning"></p-badge>
<p-badge value="6" size="xlarge" severity="success"></p-badge>
</div>
<script type="module">
const { createApp } = Vue;
const BadgeDirective = primevue.badgedirective;
const App = {
components: {
"p-badge": primevue.badge,
"p-button": primevue.button
}
};
const app = createApp(App);
app.use(primevue.config.default);
app.directive('badge', BadgeDirective);
app.mount('#app');
<\\/script>`
}
}
};
}
};
</script>

48
pages/badge/index.vue Normal file
View File

@ -0,0 +1,48 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Badge</h1>
<p>Badge is a small status indicator for another element.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Numbers</h5>
<Badge value="2" class="mr-2"></Badge>
<Badge value="8" severity="success" class="mr-2"></Badge>
<Badge value="4" severity="info" class="mr-2"></Badge>
<Badge value="12" severity="warning" class="mr-2"></Badge>
<Badge value="3" severity="danger"></Badge>
<h5 class="mb-4">Positioned Badge</h5>
<i class="pi pi-bell mr-4 p-text-secondary" style="font-size: 2rem" v-badge="2"></i>
<i class="pi pi-calendar mr-4 p-text-secondary" style="font-size: 2rem" v-badge.danger="'10+'"></i>
<i class="pi pi-envelope p-text-secondary" style="font-size: 2rem" v-badge.danger></i>
<h5>Button Badge</h5>
<Button type="button" label="Emails" badge="8" class="mr-2" />
<Button type="button" label="Messages" icon="pi pi-users" class="p-button-warning" badge="8" badgeClass="p-badge-danger" />
<h5>Sizes</h5>
<Badge value="2" class="mr-2"></Badge>
<Badge value="4" class="mr-2" size="large" severity="warning"></Badge>
<Badge value="6" size="xlarge" severity="success"></Badge>
</div>
</div>
<BadgeDoc />
</div>
</template>
<script>
import BadgeDoc from './BadgeDoc';
export default {
components: {
BadgeDoc: BadgeDoc
}
};
</script>

355
pages/blockui/BlockUIDoc.vue Executable file
View File

@ -0,0 +1,355 @@
<template>
<AppDoc name="BlockUIDemo" :sources="sources" github="blockui/BlockUIDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import BlockUI from 'primevue/blockui';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/blockui/blockui.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>
BlockUI is controlled using the <i>blocked</i> property, by default target element to block is the child component. In example below, panel gets blocked with a mask when blockedPanel is enabled and gets unblock when the bound variable is
set to false.
</p>
<pre v-code><code>
&lt;BlockUI :blocked="blockedPanel"&gt;
&lt;Panel header="Header"&gt;
Panel Content
&lt;/Panel&gt;
&lt;/BlockUI&gt;
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
blockedPanel: false
}
},
methods: {
blockPanel() {
this.blockedPanel = true;
},
unblockPanel() {
this.blockedPanel = false;
}
}
}
</code></pre>
<h5>Full Screen</h5>
<p>In full screen mode, instead of a particular element, the whole document gets blocked. Set <i>fullScreen</i> as true in order to enable this functionality.</p>
<pre v-code><code>
&lt;BlockUI :blocked="blockedDocument" :fullScreen="true"&gt;&lt;/BlockUI&gt;
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>blocked</td>
<td>array</td>
<td>null</td>
<td>Controls the blocked state.</td>
</tr>
<tr>
<td>fullscreen</td>
<td>menuitem</td>
<td>null</td>
<td>When enabled, the whole document gets blocked.</td>
</tr>
<tr>
<td>baseZIndex</td>
<td>number</td>
<td>0</td>
<td>Base zIndex value to use in layering.</td>
</tr>
<tr>
<td>autoZIndex</td>
<td>boolean</td>
<td>true</td>
<td>Whether to automatically manage layering.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>block</td>
<td>-</td>
<td>Fired when the element gets blocked.</td>
</tr>
<tr>
<td>unblock</td>
<td>-</td>
<td>Fired when the element gets unblocked.</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-blockui</td>
<td>Mask element.</td>
</tr>
<tr>
<td>p-blockui-document</td>
<td>Mask element in full screen mode.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<h5>Document</h5>
<BlockUI :blocked="blockedDocument" :fullScreen="true"></BlockUI>
<Button type="button" label="Block" @click="blockDocument()"></Button>
<h5>Panel</h5>
<Button type="button" label="Block" @click="blockPanel()"></Button>
<Button type="button" label="Unblock" @click="unblockPanel()"></Button>
<BlockUI :blocked="blockedPanel">
<Panel header="Godfather I" style="margin-top: 20px">
<p>The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding.
His beloved son Michael has just come home from the war, but does not intend to become part of his father's business.
Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family,
kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.</p>
</Panel>
</BlockUI>
</div>
</template>
<script>
export default {
data() {
return {
blockedPanel: false,
blockedDocument: false
}
},
methods: {
blockDocument() {
this.blockedDocument = true;
setTimeout(() => {
this.blockedDocument = false;
}, 3000);
},
blockPanel() {
this.blockedPanel = true;
},
unblockPanel() {
this.blockedPanel = false;
}
}
}
<\\/script>
<style lang="scss" scoped>
.p-panel p {
line-height: 1.5;
margin: 0;
}
button {
margin-right: .5rem;
}
</style>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<h5>Document</h5>
<BlockUI :blocked="blockedDocument" :fullScreen="true"></BlockUI>
<Button type="button" label="Block" @click="blockDocument()"></Button>
<h5>Panel</h5>
<Button type="button" label="Block" @click="blockPanel()"></Button>
<Button type="button" label="Unblock" @click="unblockPanel()"></Button>
<BlockUI :blocked="blockedPanel">
<Panel header="Godfather I" style="margin-top: 20px">
<p>The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding.
His beloved son Michael has just come home from the war, but does not intend to become part of his father's business.
Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family,
kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.</p>
</Panel>
</BlockUI>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const blockedPanel = ref(false);
const blockedDocument = ref(false);
const blockDocument = () => {
blockedDocument.value = true;
setTimeout(() => {
blockedDocument.value = false;
}, 3000);
};
const blockPanel = () => {
blockedPanel.value = true;
};
const unblockPanel = () => {
blockedPanel.value = false;
};
return { blockedPanel, blockedDocument, blockDocument, blockPanel, unblockPanel }
}
}
<\\/script>
<style lang="scss" scoped>
.p-panel p {
line-height: 1.5;
margin: 0;
}
button {
margin-right: .5rem;
}
</style>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/blockui/blockui.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/panel/panel.min.js"><\\/script>`,
content: `<div id="app">
<h5>Document</h5>
<p-blockui :blocked="blockedDocument" :full-screen="true"></p-blockui>
<p-button type="button" label="Block" @click="blockDocument()"></p-button>
<h5>Panel</h5>
<p-button type="button" label="Block" @click="blockPanel()"></p-button>
<p-button type="button" label="Unblock" @click="unblockPanel()"></p-button>
<p-blockui :blocked="blockedPanel">
<p-panel header="Godfather I" style="margin-top: 20px">
<p>The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding.
His beloved son Michael has just come home from the war, but does not intend to become part of his father's business.
Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family,
kind and benevolent to those who give respect, but given to ruthless violence whenever anything stands against the good of the family.</p>
</p-panel>
</p-blockui>
</div>
<script type="module">
const { createApp, ref } = Vue;
const App = {
setup() {
const blockedPanel = ref(false);
const blockedDocument = ref(false);
const blockDocument = () => {
blockedDocument.value = true;
setTimeout(() => {
blockedDocument.value = false;
}, 3000);
};
const blockPanel = () => {
blockedPanel.value = true;
};
const unblockPanel = () => {
blockedPanel.value = false;
};
return { blockedPanel, blockedDocument, blockDocument, blockPanel, unblockPanel }
},
components: {
"p-blockui": primevue.blockui,
"p-panel": primevue.panel,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.p-panel p {
line-height: 1.5;
margin: 0;
}
.p-button {
margin-right: .5rem;
}
</style>
`
}
}
};
}
};
</script>

78
pages/blockui/index.vue Executable file
View File

@ -0,0 +1,78 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>BlockUI</h1>
<p>BlockUI can either block other components or the whole page.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Document</h5>
<BlockUI :blocked="blockedDocument" :fullScreen="true"></BlockUI>
<Button type="button" label="Block" @click="blockDocument()"></Button>
<h5>Panel</h5>
<Button type="button" label="Block" @click="blockPanel()"></Button>
<Button type="button" label="Unblock" @click="unblockPanel()"></Button>
<BlockUI :blocked="blockedPanel">
<Panel header="Godfather I" style="margin-top: 20px">
<p>
The story begins as Don Vito Corleone, the head of a New York Mafia family, oversees his daughter's wedding. His beloved son Michael has just come home from the war, but does not intend to become part of his father's
business. Through Michael's life the nature of the family business becomes clear. The business of the family is just like the head of the family, kind and benevolent to those who give respect, but given to ruthless
violence whenever anything stands against the good of the family.
</p>
</Panel>
</BlockUI>
</div>
</div>
<BlockUIDoc />
</div>
</template>
<script>
import BlockUIDoc from './BlockUIDoc';
export default {
data() {
return {
blockedPanel: false,
blockedDocument: false
};
},
methods: {
blockDocument() {
this.blockedDocument = true;
setTimeout(() => {
this.blockedDocument = false;
}, 3000);
},
blockPanel() {
this.blockedPanel = true;
},
unblockPanel() {
this.blockedPanel = false;
}
},
components: {
BlockUIDoc: BlockUIDoc
}
};
</script>
<style lang="scss" scoped>
.p-panel p {
line-height: 1.5;
margin: 0;
}
button {
margin-right: 0.5rem;
}
</style>

View File

@ -0,0 +1,274 @@
<template>
<AppDoc name="BreadcrumbDemo" :sources="sources" github="breadcrumb/BreadcrumbDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Breadcrumb from 'primevue/breadcrumb';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/breadcrumb/breadcrumb.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>MenuModel</h5>
<p>Breadcrumb uses the common MenuModel API to define the items, visit <router-link to="/menumodel">MenuModel API</router-link> for details.</p>
<h5>Getting Started</h5>
<p>Breadcrumb requires a collection of menuitems as its model and a home item.</p>
<pre v-code><code>
&lt;Breadcrumb :home="home" :model="items" /&gt;
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
home: {icon: 'pi pi-home', to: '/'},
items: [
{label: 'Computer'},
{label: 'Notebook'},
{label: 'Accessories'},
{label: 'Backpacks'},
{label: 'Item'}
]
}
}
}
</code></pre>
<h5>Templating</h5>
<p>Breadcrumb offers content customization with the <i>item</i> template that receives the menuitem instance from the model as a parameter.</p>
<pre v-code><code><template v-pre>
&lt;Breadcrumb :home="home" :model="items"&gt;
&lt;template #item="{item}"&gt;
&lt;a :href="item.url"&gt;{{item.label}}&lt;/a&gt;
&lt;/template&gt;
&lt;/Breadcrumb&gt;
</template>
</code></pre>
<p><i>router-link</i> with route configuration can also be used within templating for further customization.</p>
<pre v-code><code><template v-pre>
&lt;Breadcrumb :home="home" :model="items"&gt;
&lt;template #item="{item}"&gt;
&lt;router-link :to="item.to" custom v-slot="{href, route, navigate, isActive, isExactActive}"&gt;
&lt;a :href="href" @click="navigate" :class="{'active-link': isActive, 'active-link-exact": isExactActive}&gt;{{route.fullPath}}&lt;/a&gt;
&lt;/router-link&gt;
&lt;/template&gt;
&lt;/Breadcrumb&gt;
</template>
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>model</td>
<td>array</td>
<td>null</td>
<td>An array of menuitems.</td>
</tr>
<tr>
<td>home</td>
<td>menuitem</td>
<td>null</td>
<td>Configuration for the home icon.</td>
</tr>
<tr>
<td>exact</td>
<td>boolean</td>
<td>true</td>
<td>Whether to apply 'router-link-active-exact' class if route exactly matches the item path.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>item</td>
<td>item: Menuitem instance</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-breadcrumb</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-menuitem</td>
<td>Menuitem element.</td>
</tr>
<tr>
<td>p-menuitem-text</td>
<td>Label of a menuitem.</td>
</tr>
<tr>
<td>p-breadcrumb-chevron</td>
<td>Chevron element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Breadcrumb :home="home" :model="items" />
</div>
</template>
<script>
export default {
data() {
return {
home: {
icon: 'pi pi-home',
to: '/',
},
items: [
{label: 'Computer'},
{label: 'Notebook'},
{label: 'Accessories'},
{label: 'Backpacks'},
{label: 'Item'}
]
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Breadcrumb :home="home" :model="items" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const home = ref({
icon: 'pi pi-home',
to: '/',
});
const items = ref([
{label: 'Computer'},
{label: 'Notebook'},
{label: 'Accessories'},
{label: 'Backpacks'},
{label: 'Item'}
]);
return { home, items }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/vue-router@4.0.0/dist/vue-router.global.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/breadcrumb/breadcrumb.min.js"><\\/script>`,
content: `<div id="app">
<p-breadcrumb :home="home" :model="items"></p-breadcrumb>
</div>
<script type="module">
const { createApp, ref } = Vue;
const { createRouter, createWebHistory } = VueRouter;
const App = {
setup() {
const home = ref({
icon: 'pi pi-home',
to: '/',
});
const items = ref([
{label: 'Computer'},
{label: 'Notebook'},
{label: 'Accessories'},
{label: 'Backpacks'},
{label: 'Item'}
]);
return { home, items }
},
components: {
"p-breadcrumb": primevue.breadcrumb
}
};
const routes = [{ path: "/", component: App }];
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes
});
createApp(App)
.use(router)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

35
pages/breadcrumb/index.vue Executable file
View File

@ -0,0 +1,35 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Breadcrumb</h1>
<p>Breadcrumb provides contextual information about page hierarchy.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<Breadcrumb :home="home" :model="items" />
</div>
</div>
<BreadcrumbDoc />
</div>
</template>
<script>
import BreadcrumbDoc from './BreadcrumbDoc';
export default {
data() {
return {
home: { icon: 'pi pi-home', to: '/' },
items: [{ label: 'Computer' }, { label: 'Notebook' }, { label: 'Accessories' }, { label: 'Backpacks' }, { label: 'Item' }]
};
},
components: {
BreadcrumbDoc: BreadcrumbDoc
}
};
</script>

1326
pages/calendar/CalendarDoc.vue Executable file

File diff suppressed because it is too large Load Diff

157
pages/calendar/index.vue Executable file
View File

@ -0,0 +1,157 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Calendar</h1>
<p>Calendar is an input component to select a date.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Popup</h5>
<div class="p-fluid grid formgrid">
<div class="field col-12 md:col-4">
<label for="basic">Basic</label>
<Calendar inputId="basic" v-model="date1" autocomplete="off" />
</div>
<div class="field col-12 md:col-4">
<label for="dateformat">DateFormat</label>
<Calendar inputId="dateformat" v-model="date2" dateFormat="mm-dd-yy" />
</div>
<div class="field col-12 md:col-4">
<label for="icon">Icon</label>
<Calendar inputId="icon" v-model="date3" :showIcon="true" />
</div>
<div class="field col-12 md:col-4">
<label for="minmax">MinMax</label>
<Calendar inputId="minmax" v-model="date4" :minDate="minDate" :maxDate="maxDate" :manualInput="false" />
</div>
<div class="field col-12 md:col-4">
<label for="disableddays">Disabled Days</label>
<Calendar inputId="disableddays" v-model="date5" :disabledDates="invalidDates" :disabledDays="[0, 6]" :manualInput="false" />
</div>
<div class="field col-12 md:col-4">
<label for="multiple">Multiple</label>
<Calendar inputId="multiple" v-model="dates1" selectionMode="multiple" :manualInput="false" />
</div>
<div class="field col-12 md:col-4">
<label for="range">Range</label>
<Calendar inputId="range" v-model="dates2" selectionMode="range" :manualInput="false" />
</div>
<div class="field col-12 md:col-4">
<label for="buttonbar">Button Bar</label>
<Calendar inputId="buttonbar" v-model="date6" :showButtonBar="true" />
</div>
<div class="field col-12 md:col-4">
<label for="time24">Time / 24h</label>
<Calendar inputId="time24" v-model="date7" :showTime="true" :showSeconds="true" />
</div>
<div class="field col-12 md:col-4">
<label for="time12">Time / 12h</label>
<Calendar inputId="time12" v-model="date8" :timeOnly="true" hourFormat="12" />
</div>
<div class="field col-12 md:col-4">
<label for="monthpicker">Month Picker</label>
<Calendar inputId="monthpicker" v-model="date9" view="month" dateFormat="mm/yy" />
</div>
<div class="field col-12 md:col-4">
<label for="yearpicker">Year Picker</label>
<Calendar inputId="yearpicker" v-model="date10" view="year" dateFormat="yy" />
</div>
<div class="field col-12 md:col-4">
<label for="multiplemonths">Multiple Months</label>
<Calendar inputId="multiplemonths" v-model="date11" :numberOfMonths="3" :responsiveOptions="responsiveOptions" />
</div>
<div class="field col-12 md:col-4">
<label for="datetemplate">Date Template</label>
<Calendar inputId="datetemplate" v-model="date12">
<template #date="slotProps">
<strong v-if="slotProps.date.day > 10 && slotProps.date.day < 15" class="special-day">{{ slotProps.date.day }}</strong>
<template v-else>{{ slotProps.date.day }}</template>
</template>
</Calendar>
</div>
<div class="field col-12 md:col-4">
<label for="touchUI">TouchUI</label>
<Calendar inputId="touchUI" v-model="date13" :touchUI="true" />
</div>
</div>
<h5>Inline</h5>
<Calendar v-model="date14" :inline="true" :showWeek="true" />
</div>
</div>
<CalendarDoc />
</div>
</template>
<script>
import CalendarDoc from './CalendarDoc';
export default {
created() {
let today = new Date();
let month = today.getMonth();
let year = today.getFullYear();
let prevMonth = month === 0 ? 11 : month - 1;
let prevYear = prevMonth === 11 ? year - 1 : year;
let nextMonth = month === 11 ? 0 : month + 1;
let nextYear = nextMonth === 0 ? year + 1 : year;
this.minDate = new Date();
this.minDate.setMonth(prevMonth);
this.minDate.setFullYear(prevYear);
this.maxDate = new Date();
this.maxDate.setMonth(nextMonth);
this.maxDate.setFullYear(nextYear);
let invalidDate = new Date();
invalidDate.setDate(today.getDate() - 1);
this.invalidDates = [today, invalidDate];
},
data() {
return {
date1: null,
date2: null,
date3: null,
date4: null,
date5: null,
date6: null,
date7: null,
date8: null,
date9: null,
date10: null,
date11: null,
date12: null,
date13: null,
date14: null,
dates1: null,
dates2: null,
minDate: null,
maxDate: null,
invalidDates: null,
responsiveOptions: [
{
breakpoint: '1400px',
numMonths: 2
},
{
breakpoint: '1200px',
numMonths: 1
}
]
};
},
components: {
CalendarDoc: CalendarDoc
}
};
</script>
<style scoped>
.special-day {
text-decoration: line-through;
}
</style>

288
pages/card/CardDoc.vue Executable file
View File

@ -0,0 +1,288 @@
<template>
<AppDoc name="CardDemo" :sources="sources" github="card/CardDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Card from 'primevue/card';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/card/card.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Card provides <i>header</i>, <i>title</i>, <i>subtitle</i>, <i>content</i> and <i>footer</i> as the named templates to place content.</p>
<pre v-code><code>
&lt;Card&gt;
&lt;template #header&gt;
&lt;img alt="user header" src="demo/images/usercard.png"&gt;
&lt;/template&gt;
&lt;template #title&gt;
Advanced Card
&lt;/template&gt;
&lt;template #content&gt;
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!
&lt;/template&gt;
&lt;template #footer&gt;
&lt;Button icon="pi pi-check" label="Save" /&gt;
&lt;Button icon="pi pi-times" label="Cancel" class="p-button-secondary" style="margin-left: .5em" /&gt;
&lt;/template&gt;
&lt;/Card&gt;
</code></pre>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>header</td>
<td>-</td>
</tr>
<tr>
<td>title</td>
<td>-</td>
</tr>
<tr>
<td>subtitle</td>
<td>-</td>
</tr>
<tr>
<td>content</td>
<td>-</td>
</tr>
<tr>
<td>footer</td>
<td>-</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-card</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-card-title</td>
<td>Title element.</td>
</tr>
<tr>
<td>p-card-subtitle</td>
<td>Subtitle element.</td>
</tr>
<tr>
<td>p-card-content</td>
<td>Content of the card.</td>
</tr>
<tr>
<td>p-card-footer</td>
<td>Footer of the card.</td>
</tr>
</tbody>
</table>
</div>
<h5>Accessibility</h5>
<DevelopmentSection>
<h6>Screen Reader</h6>
<p>
A card can be utilized in many use cases as a result no role is enforced, in fact a role may not be necessary if the card is used for presentational purposes only. Any valid attribute is passed to the container element so if you
require to use one of the <a href="https://www.w3.org/TR/wai-aria/#landmark" alt="Landmark Roles">landmark</a> roles like <i>region</i>, you may use the <i>role</i> property.
</p>
<pre v-code><code>
&lt;Card role="region"&gt;
Content
&lt;/Card&gt;
</code></pre>
<h5>Keyboard Support</h5>
<p>Component does not include any interactive elements.</p>
</DevelopmentSection>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Card style="width: 25rem; margin-bottom: 2em">
<template #title>
Simple Card
</template>
<template #content>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!</p>
</template>
</Card>
<Card style="width: 25em">
<template #header>
<img src="https://www.primefaces.org/wp-content/uploads/2020/02/primefacesorg-primevue-2020.png" style="height: 15rem" />
</template>
<template #title>
Advanced Card
</template>
<template #subtitle>
Card subtitle
</template>
<template #content>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!</p>
</template>
<template #footer>
<Button icon="pi pi-check" label="Save" />
<Button icon="pi pi-times" label="Cancel" class="p-button-secondary" style="margin-left: .5em" />
</template>
</Card>
</div>
</template>
<script>
export default {
}
<\\/script>
<style lang="scss" scoped>
p {
line-height: 1.5;
margin: 0;
}
</style>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Card style="width: 25rem; margin-bottom: 2em">
<template #title>
Simple Card
</template>
<template #content>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!</p>
</template>
</Card>
<Card style="width: 25em">
<template #header>
<img src="https://www.primefaces.org/wp-content/uploads/2020/02/primefacesorg-primevue-2020.png" style="height: 15rem" />
</template>
<template #title>
Advanced Card
</template>
<template #subtitle>
Card subtitle
</template>
<template #content>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!</p>
</template>
<template #footer>
<Button icon="pi pi-check" label="Save" />
<Button icon="pi pi-times" label="Cancel" class="p-button-secondary" style="margin-left: .5em" />
</template>
</Card>
</div>
</template>
<script>
export default {
}
<\\/script>
<style lang="scss" scoped>
p {
line-height: 1.5;
margin: 0;
}
</style>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/card/card.min.js"><\\/script>`,
content: `<div id="app">
<p-card style="width: 25rem; margin-bottom: 2em">
<template #title>
Simple Card
</template>
<template #content>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!</p>
</template>
</p-card>
<p-card style="width: 25em">
<template #header>
<img alt="user header" src="https://www.primefaces.org/wp-content/uploads/2020/02/primefacesorg-primevue-2020.png" style="height: 15rem">
</template>
<template #title>
Advanced Card
</template>
<template #subtitle>
Card subtitle
</template>
<template #content>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt
quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque quas!</p>
</template>
<template #footer>
<p-button icon="pi pi-check" label="Save"></p-button>
<p-button icon="pi pi-times" label="Cancel" class="p-button-secondary" style="margin-left: .5em"></p-button>
</template>
</p-card>
</div>
<script type="module">
const { createApp } = Vue;
const App = {
components: {
"p-card": primevue.card,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>`
}
}
};
}
};
</script>

60
pages/card/index.vue Executable file
View File

@ -0,0 +1,60 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Card</h1>
<p>Card is a flexible container component.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<Card style="width: 25rem; margin-bottom: 2em">
<template #title> Simple Card </template>
<template #content>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque
quas!
</p>
</template>
</Card>
<Card style="width: 25em">
<template #header>
<img alt="user header" src="demo/images/usercard.png" />
</template>
<template #title> Advanced Card </template>
<template #subtitle> Card subtitle </template>
<template #content>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse, cupiditate neque
quas!
</p>
</template>
<template #footer>
<Button icon="pi pi-check" label="Save" />
<Button icon="pi pi-times" label="Cancel" class="p-button-secondary" style="margin-left: 0.5em" />
</template>
</Card>
</div>
<CardDoc />
</div>
</template>
<script>
import CardDoc from './CardDoc';
export default {
components: {
CardDoc: CardDoc
}
};
</script>
<style lang="scss" scoped>
p {
line-height: 1.5;
margin: 0;
}
</style>

750
pages/carousel/CarouselDoc.vue Executable file
View File

@ -0,0 +1,750 @@
<template>
<AppDoc name="CarouselDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="carousel/CarouselDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Carousel from 'primevue/carousel';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/carousel/carousel.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Carousel requires a collection of items as its value along with a template to render each item.</p>
<pre v-code><code>
&lt;Carousel :value="cars"&gt;
&lt;template #item="slotProps"&gt;
&lt;/template&gt;
&lt;/Carousel&gt;
</code></pre>
<h5>Items per page and Scroll Items</h5>
<p>Number of items per page is defined using the <i>numVisible</i> property whereas number of items to scroll is defined with the <i>numScroll</i> property.</p>
<pre v-code><code>
&lt;Carousel :value="cars" :numVisible="3" :numScroll="1"&gt;
&lt;template #item="slotProps"&gt;
&lt;/template&gt;
&lt;/Carousel&gt;
</code></pre>
<h5>Responsive</h5>
<p>For responsive design, <i>numVisible</i> and <i>numScroll</i> can be defined using the <i>responsiveOptions</i> property that should be an array of objects whose breakpoint defines the max-width to apply the settings.</p>
<pre v-code><code><template v-pre>
&lt;Carousel :value="cars" :numVisible="4" :numScroll="3" :responsiveOptions="responsiveOptions"&gt;
&lt;template #header&gt;
&lt;h2&gt;Basic&lt;/h2&gt;
&lt;/template&gt;
&lt;template #item="slotProps"&gt;
&lt;div class="car-item"&gt;
&lt;div class="car-content"&gt;
&lt;div&gt;
&lt;img :src="'demo/images/car/' + slotProps.data.brand + '.png'" :alt="slotProps.data.brand" /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class="car-title"&gt;{{slotProps.data.brand}}&lt;/div&gt;
&lt;div class="car-subtitle"&gt;{{slotProps.data.year}} | {{slotProps.data.color}}&lt;/div&gt;
&lt;div class="car-buttons"&gt;
&lt;Button icon="pi pi-search" class="p-button-secondary" /&gt;
&lt;Button icon="pi pi-star-fill" class="p-button-secondary" /&gt;
&lt;Button icon="pi pi-cog" class="p-button-secondary" /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/Carousel&gt;
</template>
</code></pre>
<pre v-code.script><code>
data() {
return {
responsiveOptions: [
{
breakpoint: '1024px',
numVisible: 3,
numScroll: 3
},
{
breakpoint: '600px',
numVisible: 2,
numScroll: 2
},
{
breakpoint: '480px',
numVisible: 1,
numScroll: 1
}
]
}
},
</code></pre>
<h5>Header and Footer</h5>
<p>Custom content projection is available using the <i>item</i>, <i>header</i> and <i>footer</i> templates.</p>
<pre v-code><code>
&lt;Carousel :value="cars" :numVisible="3" :numScroll="1" :responsiveOptions="responsiveOptions"&gt;
&lt;template #header&gt;
&lt;h2&gt;Custom Header&lt;/h2&gt;
&lt;/template&gt;
&lt;template #item="slotProps"&gt;
Content
&lt;/template&gt;
&lt;template #footer&gt;
&lt;h2&gt;Custom Footer&lt;/h2&gt;
&lt;/template&gt;
&lt;/Carousel&gt;
</code></pre>
<h5>Orientation</h5>
<p>Default layout of the Carousel is horizontal, other possible option is the vertical mode that is configured with the <i>orientation</i> property.</p>
<pre v-code><code>
&lt;Carousel :value="cars" :numVisible="1" :numScroll="1" orientation="vertical" verticalViewPortHeight="330px" :responsiveOptions="responsiveOptions"&gt;
&lt;template #item="slotProps"&gt;
Content
&lt;/template&gt;
&lt;/Carousel&gt;
</code></pre>
<h5>AutoPlay and Circular</h5>
<p>When <i>autoplayInterval</i> is defined in milliseconds, items are scrolled automatically. In addition, for infinite scrolling <i>circular</i> property needs to be enabled. Note that in autoplay mode, circular is enabled by default.</p>
<pre v-code><code>
&lt;Carousel :value="cars" :numVisible="3" :numScroll="1" :circular="true" :autoplayInterval="3000"&gt;
&lt;template #header&gt;
&lt;h2&gt;Circular, AutoPlay&lt;/h2&gt;
&lt;/template&gt;
&lt;template #item="slotProps"&gt;
Content
&lt;/template&gt;
&lt;/Carousel&gt;
</code></pre>
<h5>Properties</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>value</td>
<td>array</td>
<td>null</td>
<td>An array of objects to display.</td>
</tr>
<tr>
<td>page</td>
<td>number</td>
<td>null</td>
<td>Index of the first item.</td>
</tr>
<tr>
<td>circular</td>
<td>boolean</td>
<td>false</td>
<td>Defines if scrolling would be infinite.</td>
</tr>
<tr>
<td>autoplayInterval</td>
<td>number</td>
<td>null</td>
<td>Time in milliseconds to scroll items automatically.</td>
</tr>
<tr>
<td>numVisible</td>
<td>number</td>
<td>1</td>
<td>Number of items per page.</td>
</tr>
<tr>
<td>numScroll</td>
<td>number</td>
<td>1</td>
<td>Number of items to scroll.</td>
</tr>
<tr>
<td>responsiveOptions</td>
<td>any</td>
<td>null</td>
<td>An array of options for responsive design.</td>
</tr>
<tr>
<td>orientation</td>
<td>string</td>
<td>horizontal</td>
<td>Specifies the layout of the component, valid values are "horizontal" and "vertical".</td>
</tr>
<tr>
<td>verticalViewPortHeight</td>
<td>string</td>
<td>300px</td>
<td>Height of the viewport in vertical layout.</td>
</tr>
<tr>
<td>contentClass</td>
<td>string</td>
<td>null</td>
<td>Style class of main content.</td>
</tr>
<tr>
<td>containerClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the viewport container.</td>
</tr>
<tr>
<td>indicatorsContentClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the indicator items.</td>
</tr>
<tr>
<td>showNavigators</td>
<td>boolean</td>
<td>true</td>
<td>Whether to display navigation buttons in container.</td>
</tr>
<tr>
<td>showIndicators</td>
<td>boolean</td>
<td>true</td>
<td>Whether to display indicator container.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>header</td>
<td>-</td>
</tr>
<tr>
<td>item</td>
<td>
data: Data of the component<br />
index: Index of the item
</td>
</tr>
<tr>
<td>footer</td>
<td>-</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-carousel</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-carousel-header</td>
<td>Header section.</td>
</tr>
<tr>
<td>p-carousel-footer</td>
<td>Footer section.</td>
</tr>
<tr>
<td>p-carousel-content</td>
<td>Main content element. It contains the container of the viewport.</td>
</tr>
<tr>
<td>p-carousel-container</td>
<td>Container of the viewport. It contains navigation buttons and viewport.</td>
</tr>
<tr>
<td>p-carousel-items-content</td>
<td>Viewport.</td>
</tr>
<tr>
<td>p-carousel-indicators</td>
<td>Container of the indicators.</td>
</tr>
<tr>
<td>p-carousel-indicator</td>
<td>Indicator element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<Carousel :value="products" :numVisible="3" :numScroll="3" :responsiveOptions="responsiveOptions">
<template #header>
<h5>Basic</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
<div class="card">
<Carousel :value="products" :numVisible="3" :numScroll="1" :responsiveOptions="responsiveOptions" class="custom-carousel" :circular="true" :autoplayInterval="3000">
<template #header>
<h5>Circular, AutoPlay, 3 Items per Page and Scroll by 1</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
<div class="card">
<Carousel :value="products" :numVisible="1" :numScroll="1" orientation="vertical" verticalViewPortHeight="430px"
style="max-width: 400px; margin-top: 2em">
<template #header>
<h5>Vertical</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null,
responsiveOptions: [
{
breakpoint: '1024px',
numVisible: 3,
numScroll: 3
},
{
breakpoint: '600px',
numVisible: 2,
numScroll: 2
},
{
breakpoint: '480px',
numVisible: 1,
numScroll: 1
}
]
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data.slice(0,9));
}
}
<\\/script>
<style lang="scss" scoped>
.product-item {
.product-item-content {
border: 1px solid var(--surface-border);
border-radius: 3px;
margin: .3rem;
text-align: center;
padding: 2rem 0;
}
.product-image {
width: 50%;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
}
</style>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<Carousel :value="products" :numVisible="3" :numScroll="3" :responsiveOptions="responsiveOptions">
<template #header>
<h5>Basic</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
<div class="card">
<Carousel :value="products" :numVisible="3" :numScroll="1" :responsiveOptions="responsiveOptions" class="custom-carousel" :circular="true" :autoplayInterval="3000">
<template #header>
<h5>Circular, AutoPlay, 3 Items per Page and Scroll by 1</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
<div class="card">
<Carousel :value="products" :numVisible="1" :numScroll="1" orientation="vertical" verticalViewPortHeight="430px"
style="max-width: 400px; margin-top: 2em">
<template #header>
<h5>Vertical</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data.slice(0,9));
})
const products = ref(null);
const productService = ref(new ProductService());
const responsiveOptions = ref([
{
breakpoint: '1024px',
numVisible: 3,
numScroll: 3
},
{
breakpoint: '600px',
numVisible: 2,
numScroll: 2
},
{
breakpoint: '480px',
numVisible: 1,
numScroll: 1
}
]);
return {products, productService, responsiveOptions }
}
}
<\\/script>
<style lang="scss" scoped>
.product-item {
.product-item-content {
border: 1px solid var(--surface-border);
border-radius: 3px;
margin: .3rem;
text-align: center;
padding: 2rem 0;
}
.product-image {
width: 50%;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
}
</style>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/carousel/carousel.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<p-carousel :value="products" :num-visible="3" :num-scroll="3" :responsive-options="responsiveOptions">
<template #header>
<h5>Basic</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<p-button icon="pi pi-search" class="p-button p-button-rounded mr-2"></p-button>
<p-button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2"></p-button>
<p-button icon="pi pi-cog" class="p-button-help p-button-rounded"></p-button>
</div>
</div>
</div>
</div>
</template>
</p-carousel>
</div>
<div class="card">
<p-carousel :value="products" :num-visible="3" :num-scroll="1" :responsive-options="responsiveOptions" class="custom-carousel" :circular="true" :autoplay-interval="3000">
<template #header>
<h5>Circular, AutoPlay, 3 Items per Page and Scroll by 1</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<p-button icon="pi pi-search" class="p-button p-button-rounded mr-2"></p-button>
<p-button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2"></p-button>
<p-button icon="pi pi-cog" class="p-button-help p-button-rounded"></p-button>
</div>
</div>
</div>
</div>
</template>
</p-carousel>
</div>
<div class="card">
<p-carousel :value="products" :num-visible="1" :num-scroll="1" orientation="vertical" vertical-view-portHeight="430px"
style="max-width: 400px; margin-top: 2em">
<template #header>
<h5>Vertical</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{slotProps.data.name}}</h4>
<h6 class="mt-0 mb-3">\${{slotProps.data.price}}</h6>
<span :class="'product-badge status-'+slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
<div class="car-buttons mt-5">
<p-button icon="pi pi-search" class="p-button p-button-rounded mr-2"></p-button>
<p-button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2"></p-button>
<p-button icon="pi pi-cog" class="p-button-help p-button-rounded"></p-button>
</div>
</div>
</div>
</div>
</template>
</p-carousel>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data.slice(0,9));
})
const products = ref(null);
const productService = ref(new ProductService());
const responsiveOptions = ref([
{
breakpoint: '1024px',
numVisible: 3,
numScroll: 3
},
{
breakpoint: '600px',
numVisible: 2,
numScroll: 2
},
{
breakpoint: '480px',
numVisible: 1,
numScroll: 1
}
]);
return {products, productService, responsiveOptions }
},
components: {
"p-carousel": primevue.carousel,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.product-item .product-item-content {
border: 1px solid var(--surface-border);
border-radius: 3px;
margin: .3rem;
text-align: center;
padding: 2rem 0;
}
.product-item .product-image {
width: 50%;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
</style>
`
}
}
};
}
};
</script>

153
pages/carousel/index.vue Executable file
View File

@ -0,0 +1,153 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Carousel</h1>
<p>Carousel is a content slider featuring various customization options.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<Carousel :value="products" :numVisible="3" :numScroll="3" :responsiveOptions="responsiveOptions">
<template #header>
<h5>Basic</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{ slotProps.data.name }}</h4>
<h6 class="mt-0 mb-3">${{ slotProps.data.price }}</h6>
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{ slotProps.data.inventoryStatus }}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
<div class="card">
<Carousel :value="products" :numVisible="3" :numScroll="1" :responsiveOptions="responsiveOptions" class="custom-carousel" :circular="true" :autoplayInterval="3000">
<template #header>
<h5>Circular, AutoPlay, 3 Items per Page and Scroll by 1</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{ slotProps.data.name }}</h4>
<h6 class="mt-0 mb-3">${{ slotProps.data.price }}</h6>
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{ slotProps.data.inventoryStatus }}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
<div class="card">
<Carousel :value="products" :numVisible="1" :numScroll="1" orientation="vertical" verticalViewPortHeight="352px" style="max-width: 400px; margin-top: 2em">
<template #header>
<h5>Vertical</h5>
</template>
<template #item="slotProps">
<div class="product-item">
<div class="product-item-content">
<div class="mb-3">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.name" class="product-image" />
</div>
<div>
<h4 class="mb-1">{{ slotProps.data.name }}</h4>
<h6 class="mt-0 mb-3">${{ slotProps.data.price }}</h6>
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{ slotProps.data.inventoryStatus }}</span>
<div class="car-buttons mt-5">
<Button icon="pi pi-search" class="p-button p-button-rounded mr-2" />
<Button icon="pi pi-star-fill" class="p-button-success p-button-rounded mr-2" />
<Button icon="pi pi-cog" class="p-button-help p-button-rounded" />
</div>
</div>
</div>
</div>
</template>
</Carousel>
</div>
</div>
<CarouselDoc />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
import CarouselDoc from './CarouselDoc';
export default {
data() {
return {
products: null,
responsiveOptions: [
{
breakpoint: '1024px',
numVisible: 3,
numScroll: 3
},
{
breakpoint: '600px',
numVisible: 2,
numScroll: 2
},
{
breakpoint: '480px',
numVisible: 1,
numScroll: 1
}
]
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data.slice(0, 9)));
},
components: {
CarouselDoc: CarouselDoc
}
};
</script>
<style lang="scss" scoped>
.product-item {
.product-item-content {
border: 1px solid var(--surface-border);
border-radius: 3px;
margin: 0.3rem;
text-align: center;
padding: 2rem 0;
}
.product-image {
width: 50%;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
}
</style>

View File

@ -0,0 +1,989 @@
<template>
<AppDoc name="CascadeSelectDemo" :sources="sources" github="cascadeselect/CascadeSelectDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import CascadeSelect from 'primevue/cascadeselect';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/cascadeselect/cascadeselect.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>
CascadeSelect requires a value to bind and a collection of arbitrary objects with a nested hierarchy. <i>optionGroupLabel</i> is used for the text of a category and <i>optionGroupChildren</i> is to define the children of the category.
Note that order of the <i>optionGroupChildren</i> matters and it should correspond to the data hierarchy.
</p>
<pre v-code><code>
&lt;CascadeSelect v-model="selectedCity" :options="countries" optionLabel="cname" optionGroupLabel="name"
:optionGroupChildren="['states', 'cities']" style="minWidth: 14rem" &gt;
</code></pre>
<pre v-code.script><code>
data() &#123;
return &#123;
selectedCity: null,
countries: [
&#123;
name: 'Australia',
code: 'AU',
states: [
&#123;
name: 'New South Wales',
cities: [
&#123;cname: 'Sydney', code: 'A-SY'&#125;,
&#123;cname: 'Newcastle', code: 'A-NE'&#125;,
&#123;cname: 'Wollongong', code: 'A-WO'&#125;
]
&#125;,
&#123;
name: 'Queensland',
cities: [
&#123;cname: 'Brisbane', code: 'A-BR'&#125;,
&#123;cname: 'Townsville', code: 'A-TO'&#125;
]
&#125;,
]
&#125;,
&#123;
name: 'Canada',
code: 'CA',
states: [
&#123;
name: 'Quebec',
cities: [
&#123;cname: 'Montreal', code: 'C-MO'&#125;,
&#123;cname: 'Quebec City', code: 'C-QU'&#125;
]
&#125;,
&#123;
name: 'Ontario',
cities: [
&#123;cname: 'Ottawa', code: 'C-OT'&#125;,
&#123;cname: 'Toronto', code: 'C-TO'&#125;
]
&#125;,
]
&#125;,
&#123;
name: 'United States',
code: 'US',
states: [
&#123;
name: 'California',
cities: [
&#123;cname: 'Los Angeles', code: 'US-LA'&#125;,
&#123;cname: 'San Diego', code: 'US-SD'&#125;,
&#123;cname: 'San Francisco', code: 'US-SF'&#125;
]
&#125;,
&#123;
name: 'Florida',
cities: [
&#123;cname: 'Jacksonville', code: 'US-JA'&#125;,
&#123;cname: 'Miami', code: 'US-MI'&#125;,
&#123;cname: 'Tampa', code: 'US-TA'&#125;,
&#123;cname: 'Orlando', code: 'US-OR'&#125;
]
&#125;,
&#123;
name: 'Texas',
cities: [
&#123;cname: 'Austin', code: 'US-AU'&#125;,
&#123;cname: 'Dallas', code: 'US-DA'&#125;,
&#123;cname: 'Houston', code: 'US-HO'&#125;
]
&#125;
]
&#125;
]
&#125;
}
</code></pre>
<h5>Templating</h5>
<p>Content of an item can be customized with the <i>option</i> template.</p>
<pre v-code><code><template v-pre>
&lt;CascadeSelect v-model="selectedCity" :options="countries" optionLabel="cname" optionGroupLabel="name"
:optionGroupChildren="['states', 'cities']" style="minWidth: 14rem"&gt;
&lt;template #option="slotProps"&gt;
&lt;div class="country-item"&gt;
&lt;img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.option.code.toLowerCase()" v-if="slotProps.option.states" /&gt;
&lt;i class="pi pi-compass mr-2" v-if="slotProps.option.cities"&gt;&lt;/i&gt;
&lt;i class="pi pi-map-marker mr-2" v-if="slotProps.option.cname"&gt;&lt;/i&gt;
&lt;span&gt;{{slotProps.option.cname || slotProps.option.name}}&lt;/span&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/CascadeSelect&gt;
</template>
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>modelValue</td>
<td>any</td>
<td>null</td>
<td>Value of the component.</td>
</tr>
<tr>
<td>options</td>
<td>array</td>
<td>null</td>
<td>An array of selectitems to display as the available options.</td>
</tr>
<tr>
<td>optionLabel</td>
<td>string | function</td>
<td>null</td>
<td>Property name or getter function to use as the label of an option.</td>
</tr>
<tr>
<td>optionValue</td>
<td>string | function</td>
<td>null</td>
<td>Property name or getter function to use as the value of an option, defaults to the option itself when not defined.</td>
</tr>
<tr>
<td>optionDisabled</td>
<td>string | function</td>
<td>null</td>
<td>Property name or getter function to use as the disabled flag of an option, defaults to false when not defined.</td>
</tr>
<tr>
<td>optionGroupLabel</td>
<td>string | function</td>
<td>null</td>
<td>Property name or getter function to use as the label of an option group.</td>
</tr>
<tr>
<td>optionGroupChildren</td>
<td>array | function</td>
<td>null</td>
<td>Property name or getter function to retrieve the items of a group.</td>
</tr>
<tr>
<td>placeholder</td>
<td>string</td>
<td>null</td>
<td>Default text to display when no option is selected.</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>false</td>
<td>When present, it specifies that the component should be disabled.</td>
</tr>
<tr>
<td>dataKey</td>
<td>string</td>
<td>null</td>
<td>A property to uniquely identify an option.</td>
</tr>
<tr>
<td>inputId</td>
<td>string</td>
<td>null</td>
<td>Identifier of the underlying input element.</td>
</tr>
<tr>
<td>inputStyle</td>
<td>any</td>
<td>null</td>
<td>Inline style of the input field.</td>
</tr>
<tr>
<td>inputClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the input field.</td>
</tr>
<tr>
<td>inputProps</td>
<td>object</td>
<td>null</td>
<td>Uses to pass all properties of the HTMLInputElement/HTMLSpanElement to the focusable input element inside the component.</td>
</tr>
<tr>
<td>panelStyle</td>
<td>any</td>
<td>null</td>
<td>Inline style of the overlay panel.</td>
</tr>
<tr>
<td>panelClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the overlay panel.</td>
</tr>
<tr>
<td>panelProps</td>
<td>object</td>
<td>null</td>
<td>Uses to pass all properties of the HTMLDivElement to the overlay panel.</td>
</tr>
<tr>
<td>appendTo</td>
<td>string</td>
<td>body</td>
<td>A valid query selector or an HTMLElement to specify where the overlay gets attached. Special keywords are "body" for document body and "self" for the element itself.</td>
</tr>
<tr>
<td>loading</td>
<td>boolean</td>
<td>false</td>
<td>Whether the dropdown is in loading state.</td>
</tr>
<tr>
<td>loadingIcon</td>
<td>string</td>
<td>pi pi-spinner pi-spin</td>
<td>Icon to display in loading state.</td>
</tr>
<tr>
<td>autoOptionFocus</td>
<td>boolean</td>
<td>true</td>
<td>Whether to focus on the first visible or selected element when the overlay panel is shown.</td>
</tr>
<tr>
<td>selectOnFocus</td>
<td>boolean</td>
<td>false</td>
<td>When enabled, the focused option is selected/opened.</td>
</tr>
<tr>
<td>searchLocale</td>
<td>string</td>
<td>undefined</td>
<td>Locale to use in searching. The default locale is the host environment's current locale.</td>
</tr>
<tr>
<td>searchMessage</td>
<td>string</td>
<td>{0} results are available</td>
<td>Text to be displayed in hidden accessible field when filtering returns any results. Defaults to value from PrimeVue locale configuration.</td>
</tr>
<tr>
<td>selectionMessage</td>
<td>string</td>
<td>{0} items selected</td>
<td>Text to be displayed in hidden accessible field when options are selected. Defaults to value from PrimeVue locale configuration.</td>
</tr>
<tr>
<td>emptySelectionMessage</td>
<td>string</td>
<td>No selected item</td>
<td>Text to be displayed in hidden accessible field when any option is not selected. Defaults to value from PrimeVue locale configuration.</td>
</tr>
<tr>
<td>emptySearchMessage</td>
<td>string</td>
<td>No results found</td>
<td>Text to be displayed when filtering does not return any results. Defaults to value from PrimeVue locale configuration.</td>
</tr>
<tr>
<td>emptyMessage</td>
<td>string</td>
<td>No available options</td>
<td>Text to be displayed when there are no options available. Defaults to value from PrimeVue locale configuration.</td>
</tr>
<tr>
<td>tabindex</td>
<td>number</td>
<td>0</td>
<td>Index of the element in tabbing order.</td>
</tr>
<tr>
<td>aria-label</td>
<td>string</td>
<td>null</td>
<td>Defines a string value that labels an interactive element.</td>
</tr>
<tr>
<td>aria-labelledby</td>
<td>string</td>
<td>null</td>
<td>Establishes relationships between the component and label(s) where its value should be one or more element IDs.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>change</td>
<td>
event.originalEvent: Original event <br />
event.value: Selected option value
</td>
<td>Callback to invoke on value change.</td>
</tr>
<tr>
<td>focus</td>
<td>event</td>
<td>Callback to invoke when the component receives focus.</td>
</tr>
<tr>
<td>blur</td>
<td>event</td>
<td>Callback to invoke when the component loses focus.</td>
</tr>
<tr>
<td>click</td>
<td>event</td>
<td>Callback to invoke on click.</td>
</tr>
<tr>
<td>group-change</td>
<td>
event.originalEvent: Original event <br />
event.value: Selected option group
</td>
<td>Callback to invoke when a group changes.</td>
</tr>
<tr>
<td>before-show</td>
<td>-</td>
<td>Callback to invoke before the overlay is shown.</td>
</tr>
<tr>
<td>before-hide</td>
<td>-</td>
<td>Callback to invoke before the overlay is hidden.</td>
</tr>
<tr>
<td>show</td>
<td>-</td>
<td>Callback to invoke when the overlay is shown.</td>
</tr>
<tr>
<td>hide</td>
<td>-</td>
<td>Callback to invoke when the overlay is hidden.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>value</td>
<td>
value: Value of the component <br />
placeholder: Placeholder text to show
</td>
</tr>
<tr>
<td>option</td>
<td>option: Option instance</td>
</tr>
<tr>
<td>indicator</td>
<td>-</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-cascadeselect</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-cascadeselect-label</td>
<td>Element to display label of selected option.</td>
</tr>
<tr>
<td>p-cascadeselect-trigger</td>
<td>Icon element.</td>
</tr>
<tr>
<td>p-cascadeselect-panel</td>
<td>Icon element.</td>
</tr>
<tr>
<td>p-cascadeselect-items-wrapper</td>
<td>Wrapper element of items list.</td>
</tr>
<tr>
<td>p-cascadeselect-items</td>
<td>List element of items.</td>
</tr>
<tr>
<td>p-cascadeselect-item</td>
<td>An item in the list.</td>
</tr>
<tr>
<td>p-overlay-open</td>
<td>Container element when overlay is visible.</td>
</tr>
</tbody>
</table>
</div>
<h5>Accessibility</h5>
<h6>Screen Reader</h6>
<p>
Value to describe the component can either be provided with <i>aria-labelledby</i> or <i>aria-label</i> props. The cascadeselect element has a <i>combobox</i> role in addition to <i>aria-haspopup</i> and <i>aria-expanded</i> attributes.
The relation between the combobox and the popup is created with <i>aria-controls</i> that refers to the id of the popup.
</p>
<p>
The popup list has an id that refers to the <i>aria-controls</i> attribute of the <i>combobox</i> element and uses <i>tree</i> as the role. Each list item has a <i>treeitem</i> role along with <i>aria-label</i>, <i>aria-selected</i> and
<i>aria-expanded</i> attributes. The container element of a treenode has the <i>group</i> role. The <i>aria-setsize</i>, <i>aria-posinset</i> and <i>aria-level</i> attributes are calculated implicitly and added to each treeitem.
</p>
<pre v-code><code>
&lt;span id="dd1"&gt;Options&lt;/span&gt;
&lt;CascadeSelect aria-labelledby="dd1" /&gt;
&lt;CascadeSelect aria-label="Options" /&gt;
</code></pre>
<h6>Closed State Keyboard Support</h6>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Key</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td><i>tab</i></td>
<td>Moves focus to the cascadeselect element.</td>
</tr>
<tr>
<td><i>space</i></td>
<td>Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.</td>
</tr>
<tr>
<td><i>enter</i></td>
<td>Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.</td>
</tr>
<tr>
<td><i>down arrow</i></td>
<td>Opens the popup and moves visual focus to the selected option, if there is none then first option receives the focus.</td>
</tr>
<tr>
<td><i>up arrow</i></td>
<td>Opens the popup and moves visual focus to the selected option, if there is none then last option receives the focus.</td>
</tr>
<tr>
<td><i>any printable character</i></td>
<td>Opens the popup and moves focus to the option whose label starts with the characters being typed, if there is none then first option receives the focus.</td>
</tr>
</tbody>
</table>
</div>
<h6>Popup Keyboard Support</h6>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Key</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td><i>tab</i></td>
<td>Hides the popup and moves focus to the next tabbable element. If there is none, the focusable option is selected and the overlay is closed then moves focus to next element in page.</td>
</tr>
<tr>
<td><i>shift</i> + <i>tab</i></td>
<td>Hides the popup and moves focus to the previous tabbable element.</td>
</tr>
<tr>
<td><i>enter</i></td>
<td>Selects the focused option and closes the popup.</td>
</tr>
<tr>
<td><i>space</i></td>
<td>Selects the focused option and closes the popup.</td>
</tr>
<tr>
<td><i>escape</i></td>
<td>Closes the popup, moves focus to the cascadeselect element.</td>
</tr>
<tr>
<td><i>down arrow</i></td>
<td>Moves focus to the next option.</td>
</tr>
<tr>
<td><i>up arrow</i></td>
<td>Moves focus to the previous option.</td>
</tr>
<tr>
<td><i>alt</i> + <i>up arrow</i></td>
<td>Selects the focused option and closes the popup, then moves focus to the cascadeselect element.</td>
</tr>
<tr>
<td><i>right arrow</i></td>
<td>If option is closed, opens the option otherwise moves focus to the first child option.</td>
</tr>
<tr>
<td><i>left arrow</i></td>
<td>If option is open, closes the option otherwise moves focus to the parent option.</td>
</tr>
<tr>
<td><i>home</i></td>
<td>Moves input cursor at the end, if not then moves focus to the first option.</td>
</tr>
<tr>
<td><i>end</i></td>
<td>Moves input cursor at the beginning, if not then moves focus to the last option.</td>
</tr>
<tr>
<td><i>any printable character</i></td>
<td>Moves focus to the option whose label starts with the characters being typed.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<CascadeSelect v-model="selectedCity1" :options="countries" optionLabel="cname" optionGroupLabel="name"
:optionGroupChildren="['states', 'cities']" style="minWidth: 14rem" placeholder="Select a City" />
<h5>Templating</h5>
<CascadeSelect v-model="selectedCity2" :options="countries" optionLabel="cname" optionGroupLabel="name"
:optionGroupChildren="['states', 'cities']" style="minWidth: 14rem" placeholder="Select a City">
<template #option="slotProps">
<div class="country-item">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" v-if="slotProps.option.states" />
<i class="pi pi-compass mr-2" v-if="slotProps.option.cities"></i>
<i class="pi pi-map-marker mr-2" v-if="slotProps.option.cname"></i>
<span>{{slotProps.option.cname || slotProps.option.name}}</span>
</div>
</template>
</CascadeSelect>
<h5>Loading State</h5>
<CascadeSelect placeholder="Loading..." loading style="minWidth: 14rem"></CascadeSelect>
</div>
</template>
<script>
export default {
data() {
return {
selectedCity1: null,
selectedCity2: null,
countries: [
{
name: 'Australia',
code: 'AU',
states: [
{
name: 'New South Wales',
cities: [
{cname: 'Sydney', code: 'A-SY'},
{cname: 'Newcastle', code: 'A-NE'},
{cname: 'Wollongong', code: 'A-WO'}
]
},
{
name: 'Queensland',
cities: [
{cname: 'Brisbane', code: 'A-BR'},
{cname: 'Townsville', code: 'A-TO'}
]
},
]
},
{
name: 'Canada',
code: 'CA',
states: [
{
name: 'Quebec',
cities: [
{cname: 'Montreal', code: 'C-MO'},
{cname: 'Quebec City', code: 'C-QU'}
]
},
{
name: 'Ontario',
cities: [
{cname: 'Ottawa', code: 'C-OT'},
{cname: 'Toronto', code: 'C-TO'}
]
},
]
},
{
name: 'United States',
code: 'US',
states: [
{
name: 'California',
cities: [
{cname: 'Los Angeles', code: 'US-LA'},
{cname: 'San Diego', code: 'US-SD'},
{cname: 'San Francisco', code: 'US-SF'}
]
},
{
name: 'Florida',
cities: [
{cname: 'Jacksonville', code: 'US-JA'},
{cname: 'Miami', code: 'US-MI'},
{cname: 'Tampa', code: 'US-TA'},
{cname: 'Orlando', code: 'US-OR'}
]
},
{
name: 'Texas',
cities: [
{cname: 'Austin', code: 'US-AU'},
{cname: 'Dallas', code: 'US-DA'},
{cname: 'Houston', code: 'US-HO'}
]
}
]
}
]
}
}
}
<\\/script>
<style>
img {
width: 18px;
margin-right: 0.5rem;
}
</style>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<CascadeSelect v-model="selectedCity1" :options="countries" optionLabel="cname" optionGroupLabel="name"
:optionGroupChildren="['states', 'cities']" style="minWidth: 14rem" placeholder="Select a City" />
<h5>Templating</h5>
<CascadeSelect v-model="selectedCity2" :options="countries" optionLabel="cname" optionGroupLabel="name"
:optionGroupChildren="['states', 'cities']" style="minWidth: 14rem" placeholder="Select a City">
<template #option="slotProps">
<div class="country-item">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" v-if="slotProps.option.states" />
<i class="pi pi-compass mr-2" v-if="slotProps.option.cities"></i>
<i class="pi pi-map-marker mr-2" v-if="slotProps.option.cname"></i>
<span>{{slotProps.option.cname || slotProps.option.name}}</span>
</div>
</template>
</CascadeSelect>
<h5>Loading State</h5>
<CascadeSelect placeholder="Loading..." loading style="minWidth: 14rem"></CascadeSelect>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const selectedCity1 = ref();
const selectedCity2 = ref();
const countries = ref([
{
name: 'Australia',
code: 'AU',
states: [
{
name: 'New South Wales',
cities: [
{cname: 'Sydney', code: 'A-SY'},
{cname: 'Newcastle', code: 'A-NE'},
{cname: 'Wollongong', code: 'A-WO'}
]
},
{
name: 'Queensland',
cities: [
{cname: 'Brisbane', code: 'A-BR'},
{cname: 'Townsville', code: 'A-TO'}
]
},
]
},
{
name: 'Canada',
code: 'CA',
states: [
{
name: 'Quebec',
cities: [
{cname: 'Montreal', code: 'C-MO'},
{cname: 'Quebec City', code: 'C-QU'}
]
},
{
name: 'Ontario',
cities: [
{cname: 'Ottawa', code: 'C-OT'},
{cname: 'Toronto', code: 'C-TO'}
]
},
]
},
{
name: 'United States',
code: 'US',
states: [
{
name: 'California',
cities: [
{cname: 'Los Angeles', code: 'US-LA'},
{cname: 'San Diego', code: 'US-SD'},
{cname: 'San Francisco', code: 'US-SF'}
]
},
{
name: 'Florida',
cities: [
{cname: 'Jacksonville', code: 'US-JA'},
{cname: 'Miami', code: 'US-MI'},
{cname: 'Tampa', code: 'US-TA'},
{cname: 'Orlando', code: 'US-OR'}
]
},
{
name: 'Texas',
cities: [
{cname: 'Austin', code: 'US-AU'},
{cname: 'Dallas', code: 'US-DA'},
{cname: 'Houston', code: 'US-HO'}
]
}
]
}
]);
return { selectedCity1, selectedCity2, countries }
}
}
<\\/script>
<style>
img {
width: 18px;
margin-right: 0.5rem;
}
</style>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/cascadeselect/cascadeselect.min.js"><\\/script>`,
content: `
<div id="app">
<h5>Basic</h5>
<p-cascadeselect v-model="selectedCity1" :options="countries" option-label="cname" option-group-label="name"
:option-group-children="['states', 'cities']" style="minWidth: 14rem" placeholder="Select a City"></p-cascadeselect>
<h5>Templating</h5>
<p-cascadeselect v-model="selectedCity2" :options="countries" option-label="cname" option-group-label="name"
:option-group-children="['states', 'cities']" style="minWidth: 14rem" placeholder="Select a City">
<template #option="slotProps">
<div class="country-item">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" v-if="slotProps.option.states" />
<i class="pi pi-compass mr-2" v-if="slotProps.option.cities"></i>
<i class="pi pi-map-marker mr-2" v-if="slotProps.option.cname"></i>
<span>{{slotProps.option.cname || slotProps.option.name}}</span>
</div>
</template>
</p-cascadeselect>
<h5>Loading State</h5>
<p-cascadeselect placeholder="Loading..." loading style="minWidth: 14rem"></p-cascadeselect>
</div>
<script type="module">
const { createApp, ref } = Vue;
const App = {
setup() {
const selectedCity1 = ref();
const selectedCity2 = ref();
const countries = ref([
{
name: 'Australia',
code: 'AU',
states: [
{
name: 'New South Wales',
cities: [
{cname: 'Sydney', code: 'A-SY'},
{cname: 'Newcastle', code: 'A-NE'},
{cname: 'Wollongong', code: 'A-WO'}
]
},
{
name: 'Queensland',
cities: [
{cname: 'Brisbane', code: 'A-BR'},
{cname: 'Townsville', code: 'A-TO'}
]
},
]
},
{
name: 'Canada',
code: 'CA',
states: [
{
name: 'Quebec',
cities: [
{cname: 'Montreal', code: 'C-MO'},
{cname: 'Quebec City', code: 'C-QU'}
]
},
{
name: 'Ontario',
cities: [
{cname: 'Ottawa', code: 'C-OT'},
{cname: 'Toronto', code: 'C-TO'}
]
},
]
},
{
name: 'United States',
code: 'US',
states: [
{
name: 'California',
cities: [
{cname: 'Los Angeles', code: 'US-LA'},
{cname: 'San Diego', code: 'US-SD'},
{cname: 'San Francisco', code: 'US-SF'}
]
},
{
name: 'Florida',
cities: [
{cname: 'Jacksonville', code: 'US-JA'},
{cname: 'Miami', code: 'US-MI'},
{cname: 'Tampa', code: 'US-TA'},
{cname: 'Orlando', code: 'US-OR'}
]
},
{
name: 'Texas',
cities: [
{cname: 'Austin', code: 'US-AU'},
{cname: 'Dallas', code: 'US-DA'},
{cname: 'Houston', code: 'US-HO'}
]
}
]
}
]);
return { selectedCity1, selectedCity2, countries }
},
components: {
"p-cascadeselect": primevue.cascadeselect
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
img {
width: 18px;
margin-right: 0.5rem;
}
</style>
`
}
}
};
}
};
</script>

View File

@ -0,0 +1,125 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>CascadeSelect</h1>
<p>CascadeSelect is a form component to select a value from a nested structure of options.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<CascadeSelect v-model="selectedCity1" :options="countries" optionLabel="cname" optionGroupLabel="name" :optionGroupChildren="['states', 'cities']" style="minwidth: 14rem" placeholder="Select a City" />
<h5>Templating</h5>
<CascadeSelect v-model="selectedCity2" :options="countries" optionLabel="cname" optionGroupLabel="name" :optionGroupChildren="['states', 'cities']" style="minwidth: 14rem" placeholder="Select a City">
<template #option="slotProps">
<div class="country-item">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.option.code.toLowerCase()" v-if="slotProps.option.states" />
<i class="pi pi-compass mr-2" v-if="slotProps.option.cities"></i>
<i class="pi pi-map-marker mr-2" v-if="slotProps.option.cname"></i>
<span>{{ slotProps.option.cname || slotProps.option.name }}</span>
</div>
</template>
</CascadeSelect>
<h5>Loading State</h5>
<CascadeSelect placeholder="Loading..." loading style="minwidth: 14rem"></CascadeSelect>
</div>
</div>
<CascadeSelectDoc />
</div>
</template>
<script>
import CascadeSelectDoc from './CascadeSelectDoc';
export default {
data() {
return {
selectedCity1: null,
selectedCity2: null,
countries: [
{
name: 'Australia',
code: 'AU',
states: [
{
name: 'New South Wales',
cities: [
{ cname: 'Sydney', code: 'A-SY' },
{ cname: 'Newcastle', code: 'A-NE' },
{ cname: 'Wollongong', code: 'A-WO' }
]
},
{
name: 'Queensland',
cities: [
{ cname: 'Brisbane', code: 'A-BR' },
{ cname: 'Townsville', code: 'A-TO' }
]
}
]
},
{
name: 'Canada',
code: 'CA',
states: [
{
name: 'Quebec',
cities: [
{ cname: 'Montreal', code: 'C-MO' },
{ cname: 'Quebec City', code: 'C-QU' }
]
},
{
name: 'Ontario',
cities: [
{ cname: 'Ottawa', code: 'C-OT' },
{ cname: 'Toronto', code: 'C-TO' }
]
}
]
},
{
name: 'United States',
code: 'US',
states: [
{
name: 'California',
cities: [
{ cname: 'Los Angeles', code: 'US-LA' },
{ cname: 'San Diego', code: 'US-SD' },
{ cname: 'San Francisco', code: 'US-SF' }
]
},
{
name: 'Florida',
cities: [
{ cname: 'Jacksonville', code: 'US-JA' },
{ cname: 'Miami', code: 'US-MI' },
{ cname: 'Tampa', code: 'US-TA' },
{ cname: 'Orlando', code: 'US-OR' }
]
},
{
name: 'Texas',
cities: [
{ cname: 'Austin', code: 'US-AU' },
{ cname: 'Dallas', code: 'US-DA' },
{ cname: 'Houston', code: 'US-HO' }
]
}
]
}
]
};
},
components: {
CascadeSelectDoc: CascadeSelectDoc
}
};
</script>

417
pages/chart/BarChartDemo.vue Executable file
View File

@ -0,0 +1,417 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>BarChart</h1>
<p>A bar chart or bar graph is a chart that presents grouped data with rectangular bars with lengths proportional to the values that they represent.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Vertical</h5>
<Chart type="bar" :data="basicData" :options="basicOptions" />
</div>
<div class="card">
<h5>Horizontal</h5>
<Chart type="bar" :data="basicData" :options="horizontalOptions" />
</div>
<div class="card">
<h5>Multi Axis</h5>
<Chart type="bar" :data="multiAxisData" :options="multiAxisOptions" />
</div>
<div class="card">
<h5>Stacked</h5>
<Chart type="bar" :data="stackedData" :options="stackedOptions" />
</div>
</div>
<BarChartDoc />
</div>
</template>
<script>
import BarChartDoc from './BarChartDoc';
import EventBus from '@/layouts/AppEventBus';
export default {
themeChangeListener: null,
mounted() {
this.themeChangeListener = (event) => {
if (event.dark) this.applyDarkTheme();
else this.applyLightTheme();
};
EventBus.on('theme-change', this.themeChangeListener);
if (this.isDarkTheme()) {
this.applyDarkTheme();
} else {
this.applyLightTheme();
}
},
beforeUnmount() {
EventBus.off('change-theme', this.themeChangeListener);
},
data() {
return {
basicData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: '#42A5F5',
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: '#FFA726',
data: [28, 48, 40, 19, 86, 27, 90]
}
]
},
multiAxisData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'Dataset 1',
backgroundColor: ['#EC407A', '#AB47BC', '#42A5F5', '#7E57C2', '#66BB6A', '#FFCA28', '#26A69A'],
yAxisID: 'y',
data: [65, 59, 80, 81, 56, 55, 10]
},
{
label: 'Dataset 2',
backgroundColor: '#78909C',
yAxisID: 'y1',
data: [28, 48, 40, 19, 86, 27, 90]
}
]
},
stackedData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
type: 'bar',
label: 'Dataset 1',
backgroundColor: '#42A5F5',
data: [50, 25, 12, 48, 90, 76, 42]
},
{
type: 'bar',
label: 'Dataset 2',
backgroundColor: '#66BB6A',
data: [21, 84, 24, 75, 37, 65, 34]
},
{
type: 'bar',
label: 'Dataset 3',
backgroundColor: '#FFA726',
data: [41, 52, 24, 74, 23, 21, 32]
}
]
},
basicOptions: null,
horizontalOptions: null,
multiAxisOptions: null,
stackedOptions: null
};
},
methods: {
isDarkTheme() {
return this.$appState.darkTheme === true;
},
applyLightTheme() {
this.basicOptions = {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
};
this.horizontalOptions = {
indexAxis: 'y',
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
};
this.multiAxisOptions = {
plugins: {
legend: {
labels: {
color: '#495057'
}
},
tooltip: {
mode: 'index',
intersect: true
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
min: 0,
max: 100,
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
grid: {
drawOnChartArea: false,
color: '#ebedef'
},
ticks: {
min: 0,
max: 100,
color: '#495057'
}
}
}
};
this.stackedOptions = {
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
stacked: true,
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
stacked: true,
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
};
},
applyDarkTheme() {
this.basicOptions = {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
},
scales: {
x: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
}
}
};
this.horizontalOptions = {
indexAxis: 'y',
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
},
scales: {
x: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
}
}
};
this.multiAxisOptions = {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
},
tooltip: {
mode: 'index',
intersect: true
}
},
scales: {
x: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
min: 0,
max: 100,
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
grid: {
drawOnChartArea: false,
color: 'rgba(255,255,255,0.2)'
},
ticks: {
min: 0,
max: 100,
color: '#ebedef'
}
}
}
};
this.stackedOptions = {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
},
tooltip: {
mode: 'index',
intersect: false
}
},
scales: {
x: {
stacked: true,
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y: {
stacked: true,
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
}
}
};
}
},
components: {
BarChartDoc: BarChartDoc
}
};
</script>

476
pages/chart/BarChartDoc.vue Executable file
View File

@ -0,0 +1,476 @@
<template>
<AppDoc name="ChartDemo" :sources="sources" :dependencies="{ 'chart.js': '3.3.2' }" component="Chart" github="chart/BarChartDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Vertical</h5>
<Chart type="bar" :data="basicData" :options="basicOptions" />
</div>
<div class="card">
<h5>Horizontal</h5>
<Chart type="bar" :data="basicData" :options="horizontalOptions" />
</div>
<div class="card">
<h5>Multi Axis</h5>
<Chart type="bar" :data="multiAxisData" :options="multiAxisOptions "/>
</div>
<div class="card">
<h5>Stacked</h5>
<Chart type="bar" :data="stackedData" :options="stackedOptions" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
basicData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: '#42A5F5',
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: '#FFA726',
data: [28, 48, 40, 19, 86, 27, 90]
}
]
},
multiAxisData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'Dataset 1',
backgroundColor: ['#EC407A','#AB47BC','#42A5F5','#7E57C2','#66BB6A','#FFCA28','#26A69A'],
yAxisID: 'y-axis-1',
data: [65, 59, 80, 81, 56, 55, 10]
}, {
label: 'Dataset 2',
backgroundColor: '#78909C',
yAxisID: 'y-axis-2',
data: [28, 48, 40, 19, 86, 27, 90]
}]
},
stackedData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
type: 'bar',
label: 'Dataset 1',
backgroundColor: '#42A5F5',
data: [50,25,12,48,90,76,42]
}, {
type: 'bar',
label: 'Dataset 2',
backgroundColor: '#66BB6A',
data: [21,84,24,75,37,65,34]
}, {
type: 'bar',
label: 'Dataset 3',
backgroundColor: '#FFA726',
data: [41,52,24,74,23,21,32]
}]
},
basicOptions: {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
},
horizontalOptions: {
indexAxis: 'y',
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
},
multiAxisOptions: {
plugins: {
legend: {
labels: {
color: '#495057'
}
},
tooltip: {
mode: 'index',
intersect: true
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
min: 0,
max: 100,
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
grid: {
drawOnChartArea: false,
color: '#ebedef'
},
ticks: {
min: 0,
max: 100,
color: '#495057'
}
}
}
},
stackedOptions: {
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
stacked: true,
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
stacked: true,
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
}
}
}
}
<\\/script>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Vertical</h5>
<Chart type="bar" :data="basicData" :options="basicOptions" />
</div>
<div class="card">
<h5>Horizontal</h5>
<Chart type="bar" :data="basicData" :options="horizontalOptions" />
</div>
<div class="card">
<h5>Multi Axis</h5>
<Chart type="bar" :data="multiAxisData" :options="multiAxisOptions "/>
</div>
<div class="card">
<h5>Stacked</h5>
<Chart type="bar" :data="stackedData" :options="stackedOptions" />
</div>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const basicData = ref({
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: '#42A5F5',
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: '#FFA726',
data: [28, 48, 40, 19, 86, 27, 90]
}
]
});
const multiAxisData = ref({
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'Dataset 1',
backgroundColor: ['#EC407A','#AB47BC','#42A5F5','#7E57C2','#66BB6A','#FFCA28','#26A69A'],
yAxisID: 'y-axis-1',
data: [65, 59, 80, 81, 56, 55, 10]
}, {
label: 'Dataset 2',
backgroundColor: '#78909C',
yAxisID: 'y-axis-2',
data: [28, 48, 40, 19, 86, 27, 90]
}]
});
const stackedData = ref({
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
type: 'bar',
label: 'Dataset 1',
backgroundColor: '#42A5F5',
data: [50,25,12,48,90,76,42]
}, {
type: 'bar',
label: 'Dataset 2',
backgroundColor: '#66BB6A',
data: [21,84,24,75,37,65,34]
}, {
type: 'bar',
label: 'Dataset 3',
backgroundColor: '#FFA726',
data: [41,52,24,74,23,21,32]
}]
});
const basicOptions = ref(
{
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
}
);
const horizontalOptions = ref(
{
indexAxis: 'y',
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
}
);
const multiAxisOptions = ref(
{
plugins: {
legend: {
labels: {
color: '#495057'
}
},
tooltip: {
mode: 'index',
intersect: true
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
min: 0,
max: 100,
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
grid: {
drawOnChartArea: false,
color: '#ebedef'
},
ticks: {
min: 0,
max: 100,
color: '#495057'
}
}
}
}
);
const stackedOptions = ref(
{
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
stacked: true,
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
stacked: true,
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
}
);
return { basicData, multiAxisData, stackedData,
basicOptions, horizontalOptions, multiAxisOptions, stackedOptions }
}
}
<\\/script>
`
}
}
};
}
};
</script>

235
pages/chart/ChartDoc.vue Executable file
View File

@ -0,0 +1,235 @@
<template>
<div class="content-section documentation">
<h1>ChartModel</h1>
<p>Chart components are based on <a href="https://www.chartjs.org/">Charts.js</a>, an open source HTML5 based charting library.</p>
<h5>Getting Started</h5>
<p>
Chart component is a wrapper around on <a href="https://www.chartjs.org/docs/3.3.2/">Chart.js 3.3.2+</a> so chart.js needs to be included in your project. For a complete documentation and samples please refer to the
<a href="https://www.chartjs.org/">chart.js website</a>.
</p>
<pre v-code.script><code>
npm install chart.js --save
</code></pre>
<h5>Import via Module</h5>
<pre v-code.script><code>
import Chart from 'primevue/chart';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/chart/chart.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Chart Types</h5>
<p>Chart type is defined using the <i>type</i> property. Currently there are 6 options available; <b>pie</b>, <b>doughnut</b>, <b>line</b>, <b>bar</b>, <b>radar</b> and <b>polarArea</b>.</p>
<h5>Data</h5>
<p>
Data of a chart is provided using a binding to the <i>data</i> property, each type has its own format of data. Here is an example of a line chart. For more information refer to the
<a href="https://www.chartjs.org/">charts.js</a> documentation.
</p>
<pre v-code><code>
&lt;Chart type="bar" :data="basicData" /&gt;
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
basicData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: '#42A5F5',
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: '#9CCC65',
data: [28, 48, 40, 19, 86, 27, 90]
}
]
}
}
}
}
</code></pre>
<h5>Options</h5>
<p>
While a series can be customized per dataset, general chart options are defined with options property. Example below adds a title and customizes the legend position of the chart. For all available options refer to the
<a href="https://www.chartjs.org/">charts.js</a> documentation.
</p>
<pre v-code><code>
&lt;Chart type="line" :data="data" :options="options" /&gt;
</code></pre>
<pre v-code.script><code>
options: {
responsive: true,
hoverMode: 'index',
stacked: false,
scales: {
yAxes: [{
type: 'linear',
display: true,
position: 'left',
id: 'y-axis-1',
},
{
type: 'linear',
display: true,
position: 'right',
id: 'y-axis-2',
gridLines: {
drawOnChartArea: false
}
}]
}
}
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following is the additional property to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>type</td>
<td>string</td>
<td>null</td>
<td>Type of the chart.</td>
</tr>
<tr>
<td>data</td>
<td>any</td>
<td>null</td>
<td>Data to display.</td>
</tr>
<tr>
<td>options</td>
<td>any</td>
<td>null</td>
<td>Options to customize the chart.</td>
</tr>
<tr>
<td>plugins</td>
<td>any</td>
<td>null</td>
<td>Used to custom plugins of the chart.</td>
</tr>
<tr>
<td>width</td>
<td>number</td>
<td>300</td>
<td>Width of the chart in non-responsive mode.</td>
</tr>
<tr>
<td>height</td>
<td>number</td>
<td>150</td>
<td>Height of the chart in non-responsive mode.</td>
</tr>
</tbody>
</table>
</div>
<h5>Methods</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>refresh</td>
<td>-</td>
<td>Redraws the graph.</td>
</tr>
<tr>
<td>reinit</td>
<td>-</td>
<td>Destroys the graph first and then creates it again.</td>
</tr>
<tr>
<td>generateLegend</td>
<td>-</td>
<td>Returns an HTML string of a legend for that chart. The legend is generated from the legendCallback in the options.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>select</td>
<td>
event: original event<br />
event.dataset: Selected dataset<br />
event.element: Selected element<br />
event.element._datasetIndex = Index of the dataset in data<br />
event.element._index = Index of the data in dataset
</td>
<td>Callback to invoke when a tab gets expanded.</td>
</tr>
<tr>
<td>loaded</td>
<td>chart instance</td>
<td>Callback to invoke when chart is loaded.</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-chart</td>
<td>Container element.</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>

140
pages/chart/ComboChartDemo.vue Executable file
View File

@ -0,0 +1,140 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Combo Chart</h1>
<p>Different chart types can be combined in the same graph.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<Chart type="bar" :data="chartData" :options="chartOptions" />
</div>
</div>
<ComboChartDoc />
</div>
</template>
<script>
import ComboChartDoc from './ComboChartDoc';
import EventBus from '@/layouts/AppEventBus';
export default {
themeChangeListener: null,
mounted() {
this.themeChangeListener = (event) => {
if (event.dark) this.applyDarkTheme();
else this.applyLightTheme();
};
EventBus.on('theme-change', this.themeChangeListener);
if (this.isDarkTheme()) {
this.applyDarkTheme();
}
},
beforeUnmount() {
EventBus.off('change-theme', this.themeChangeListener);
},
data() {
return {
chartData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
type: 'line',
label: 'Dataset 1',
borderColor: '#42A5F5',
borderWidth: 2,
fill: false,
data: [50, 25, 12, 48, 56, 76, 42]
},
{
type: 'bar',
label: 'Dataset 2',
backgroundColor: '#66BB6A',
data: [21, 84, 24, 75, 37, 65, 34],
borderColor: 'white',
borderWidth: 2
},
{
type: 'bar',
label: 'Dataset 3',
backgroundColor: '#FFA726',
data: [41, 52, 24, 74, 23, 21, 32]
}
]
},
chartOptions: this.isDarkTheme() ? this.applyDarkTheme() : this.applyLightTheme()
};
},
methods: {
isDarkTheme() {
return this.$appState.darkTheme === true;
},
applyLightTheme() {
this.chartOptions = {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
};
},
applyDarkTheme() {
this.chartOptions = {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
},
scales: {
x: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
}
}
};
}
},
components: {
ComboChartDoc: ComboChartDoc
}
};
</script>

153
pages/chart/ComboChartDoc.vue Executable file
View File

@ -0,0 +1,153 @@
<template>
<AppDoc name="ChartDemo" :sources="sources" :dependencies="{ 'chart.js': '3.3.2' }" component="Chart" github="chart/ComboChartDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Chart type="bar" :data="chartData" :options="chartOptions" />
</div>
</template>
<script>
export default {
data() {
return {
chartData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
type: 'line',
label: 'Dataset 1',
borderColor: '#42A5F5',
borderWidth: 2,
fill: false,
data: [50,25,12,48,56,76,42]
}, {
type: 'bar',
label: 'Dataset 2',
backgroundColor: '#66BB6A',
data: [21,84,24,75,37,65,34],
borderColor: 'white',
borderWidth: 2
}, {
type: 'bar',
label: 'Dataset 3',
backgroundColor: '#FFA726',
data: [41,52,24,74,23,21,32]
}]
},
chartOptions: {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
}
}
}
}
<\\/script>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Chart type="bar" :data="chartData" :options="chartOptions" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const chartData = ref({
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
type: 'line',
label: 'Dataset 1',
borderColor: '#42A5F5',
borderWidth: 2,
fill: false,
data: [50,25,12,48,56,76,42]
}, {
type: 'bar',
label: 'Dataset 2',
backgroundColor: '#66BB6A',
data: [21,84,24,75,37,65,34],
borderColor: 'white',
borderWidth: 2
}, {
type: 'bar',
label: 'Dataset 3',
backgroundColor: '#FFA726',
data: [41,52,24,74,23,21,32]
}]
});
const chartOptions = ref({
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
});
return { chartData, chartOptions }
}
}
<\\/script>`
}
}
};
}
};
</script>

View File

@ -0,0 +1,83 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DoughnutChart</h1>
<p>A doughnut chart is a variant of the pie chart, with a blank center allowing for additional information about the data as a whole to be included.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card flex justify-content-center">
<Chart type="doughnut" :data="chartData" :options="chartOptions" style="width: 40%" />
</div>
</div>
<DoughnutChartDoc />
</div>
</template>
<script>
import DoughnutChartDoc from './DoughnutChartDoc';
import EventBus from '@/layouts/AppEventBus';
export default {
themeChangeListener: null,
mounted() {
this.themeChangeListener = (event) => {
if (event.dark) this.chartOptions = this.getDarkTheme();
else this.chartOptions = this.getLightTheme();
};
EventBus.on('theme-change', this.themeChangeListener);
},
beforeUnmount() {
EventBus.off('change-theme', this.themeChangeListener);
},
data() {
return {
chartData: {
labels: ['A', 'B', 'C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56'],
hoverBackgroundColor: ['#FF6384', '#36A2EB', '#FFCE56']
}
]
},
chartOptions: this.isDarkTheme() ? this.getDarkTheme() : this.getLightTheme()
};
},
methods: {
isDarkTheme() {
return this.$appState.darkTheme === true;
},
getLightTheme() {
return {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
}
};
},
getDarkTheme() {
return {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
}
};
}
},
components: {
DoughnutChartDoc: DoughnutChartDoc
}
};
</script>

View File

@ -0,0 +1,93 @@
<template>
<AppDoc name="ChartDemo" :sources="sources" :dependencies="{ 'chart.js': '3.3.2' }" component="Chart" github="chart/DoughnutChartDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Source',
content: `
<template>
<div>
<Chart type="doughnut" :data="chartData" :options="lightOptions" />
</div>
</template>
<script>
export default {
data() {
return {
chartData: {
labels: ['A','B','C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: ["#FF6384","#36A2EB","#FFCE56"],
hoverBackgroundColor: ["#FF6384","#36A2EB","#FFCE56"]
}
]
},
lightOptions: {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
}
}
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API',
content: `
<template>
<div>
<Chart type="doughnut" :data="chartData" :options="lightOptions" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const chartData = ref({
labels: ['A','B','C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: ["#FF6384","#36A2EB","#FFCE56"],
hoverBackgroundColor: ["#FF6384","#36A2EB","#FFCE56"]
}
]
});
const lightOptions = ref({
plugins: {
legend: {
labels: {
color: '#495057'
}
}
}
});
return { chartData, lightOptions }
}
}
<\\/script>
`
}
}
};
}
};
</script>

283
pages/chart/LineChartDemo.vue Executable file
View File

@ -0,0 +1,283 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Line Chart</h1>
<p>A line chart or line graph is a type of chart which displays information as a series of data points called 'markers' connected by straight line segments.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<Chart type="line" :data="basicData" :options="basicOptions" />
</div>
<div class="card">
<h5>Multi Axis</h5>
<Chart type="line" :data="multiAxisData" :options="multiAxisOptions" />
</div>
<div class="card">
<h5>Line Styles</h5>
<Chart type="line" :data="lineStylesData" :options="basicOptions" />
</div>
</div>
<LineChartDoc />
</div>
</template>
<script>
import LineChartDoc from './LineChartDoc';
import EventBus from '@/layouts/AppEventBus';
export default {
themeChangeListener: null,
mounted() {
this.themeChangeListener = (event) => {
if (event.dark) this.applyDarkTheme();
else this.applyLightTheme();
};
EventBus.on('theme-change', this.themeChangeListener);
if (this.isDarkTheme()) {
this.applyDarkTheme();
} else {
this.applyLightTheme();
}
},
beforeUnmount() {
EventBus.off('change-theme', this.themeChangeListener);
},
data() {
return {
basicData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'First Dataset',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
borderColor: '#42A5F5',
tension: 0.4
},
{
label: 'Second Dataset',
data: [28, 48, 40, 19, 86, 27, 90],
fill: false,
borderColor: '#FFA726',
tension: 0.4
}
]
},
multiAxisData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'Dataset 1',
fill: false,
borderColor: '#42A5F5',
yAxisID: 'y',
tension: 0.4,
data: [65, 59, 80, 81, 56, 55, 10]
},
{
label: 'Dataset 2',
fill: false,
borderColor: '#00bb7e',
yAxisID: 'y1',
tension: 0.4,
data: [28, 48, 40, 19, 86, 27, 90]
}
]
},
lineStylesData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'First Dataset',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
tension: 0.4,
borderColor: '#42A5F5'
},
{
label: 'Second Dataset',
data: [28, 48, 40, 19, 86, 27, 90],
fill: false,
borderDash: [5, 5],
tension: 0.4,
borderColor: '#66BB6A'
},
{
label: 'Third Dataset',
data: [12, 51, 62, 33, 21, 62, 45],
fill: true,
borderColor: '#FFA726',
tension: 0.4,
backgroundColor: 'rgba(255,167,38,0.2)'
}
]
},
basicOptions: null,
multiAxisOptions: null
};
},
methods: {
isDarkTheme() {
return this.$appState.darkTheme === true;
},
applyLightTheme() {
this.basicOptions = {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
};
this.multiAxisOptions = {
stacked: false,
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
ticks: {
color: '#495057'
},
grid: {
drawOnChartArea: false,
color: '#ebedef'
}
}
}
};
},
applyDarkTheme() {
this.basicOptions = {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
},
scales: {
x: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
}
}
};
this.multiAxisOptions = {
stacked: false,
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
},
scales: {
x: {
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
ticks: {
color: '#ebedef'
},
grid: {
drawOnChartArea: false,
color: 'rgba(255,255,255,0.2)'
}
}
}
};
}
},
components: {
LineChartDoc: LineChartDoc
}
};
</script>

364
pages/chart/LineChartDoc.vue Executable file
View File

@ -0,0 +1,364 @@
<template>
<AppDoc name="ChartDemo" :sources="sources" :dependencies="{ 'chart.js': '3.3.2' }" component="Chart" github="chart/LineChartDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Basic</h5>
<Chart type="line" :data="basicData" :options="basicOptions" />
</div>
<div class="card">
<h5>Multi Axis</h5>
<Chart type="line" :data="multiAxisData" :options="multiAxisOptions" />
</div>
<div class="card">
<h5>Line Styles</h5>
<Chart type="line" :data="lineStylesData" :options="basicOptions" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
basicData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'First Dataset',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
borderColor: '#42A5F5',
tension: .4
},
{
label: 'Second Dataset',
data: [28, 48, 40, 19, 86, 27, 90],
fill: false,
borderColor: '#FFA726',
tension: .4
}
]
},
multiAxisData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'Dataset 1',
fill: false,
borderColor: '#42A5F5',
yAxisID: 'y',
tension: .4,
data: [65, 59, 80, 81, 56, 55, 10]
}, {
label: 'Dataset 2',
fill: false,
borderColor: '#00bb7e',
yAxisID: 'y1',
tension: .4,
data: [28, 48, 40, 19, 86, 27, 90]
}]
},
lineStylesData: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'First Dataset',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
tension: .4,
borderColor: '#42A5F5'
},
{
label: 'Second Dataset',
data: [28, 48, 40, 19, 86, 27, 90],
fill: false,
borderDash: [5, 5],
tension: .4,
borderColor: '#66BB6A'
},
{
label: 'Third Dataset',
data: [12, 51, 62, 33, 21, 62, 45],
fill: true,
borderColor: '#FFA726',
tension: .4,
backgroundColor: 'rgba(255,167,38,0.2)'
}
]
},
basicOptions: {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
},
multiAxisOptions:{
stacked: false,
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
ticks: {
color: '#495057'
},
grid: {
drawOnChartArea: false,
color: '#ebedef'
}
}
}
}
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Basic</h5>
<Chart type="line" :data="basicData" :options="basicOptions" />
</div>
<div class="card">
<h5>Multi Axis</h5>
<Chart type="line" :data="multiAxisData" :options="multiAxisOptions" />
</div>
<div class="card">
<h5>Line Styles</h5>
<Chart type="line" :data="lineStylesData" :options="basicOptions" />
</div>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const basicData = ref(
{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'First Dataset',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
borderColor: '#42A5F5',
tension: .4
},
{
label: 'Second Dataset',
data: [28, 48, 40, 19, 86, 27, 90],
fill: false,
borderColor: '#FFA726',
tension: .4
}
]
}
);
const multiAxisData = ref(
{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'Dataset 1',
fill: false,
borderColor: '#42A5F5',
yAxisID: 'y',
tension: .4,
data: [65, 59, 80, 81, 56, 55, 10]
}, {
label: 'Dataset 2',
fill: false,
borderColor: '#00bb7e',
yAxisID: 'y1',
tension: .4,
data: [28, 48, 40, 19, 86, 27, 90]
}]
}
);
const lineStylesData = ref(
{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'First Dataset',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
tension: .4,
borderColor: '#42A5F5'
},
{
label: 'Second Dataset',
data: [28, 48, 40, 19, 86, 27, 90],
fill: false,
borderDash: [5, 5],
tension: .4,
borderColor: '#66BB6A'
},
{
label: 'Third Dataset',
data: [12, 51, 62, 33, 21, 62, 45],
fill: true,
borderColor: '#FFA726',
tension: .4,
backgroundColor: 'rgba(255,167,38,0.2)'
}
]
}
);
const basicOptions = ref(
{
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
}
}
}
);
const multiAxisOptions = ref(
{
stacked: false,
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
x: {
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
ticks: {
color: '#495057'
},
grid: {
color: '#ebedef'
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
ticks: {
color: '#495057'
},
grid: {
drawOnChartArea: false,
color: '#ebedef'
}
}
}
}
);
return { basicData, multiAxisData, multiAxisOptions, lineStylesData, basicOptions }
}
}
<\\/script>
`
}
}
};
}
};
</script>

83
pages/chart/PieChartDemo.vue Executable file
View File

@ -0,0 +1,83 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Pie Chart</h1>
<p>A pie chart is a circular statistical graphic, which is divided into slices to illustrate numerical proportion.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card flex justify-content-center">
<Chart type="pie" :data="chartData" :options="chartOptions" style="width: 40%" />
</div>
</div>
<PieChartDoc />
</div>
</template>
<script>
import PieChartDoc from './PieChartDoc';
import EventBus from '@/layouts/AppEventBus';
export default {
themeChangeListener: null,
mounted() {
this.themeChangeListener = (event) => {
if (event.dark) this.chartOptions = this.getDarkTheme();
else this.chartOptions = this.getLightTheme();
};
EventBus.on('theme-change', this.themeChangeListener);
},
beforeUnmount() {
EventBus.off('change-theme', this.themeChangeListener);
},
data() {
return {
chartData: {
labels: ['A', 'B', 'C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: ['#42A5F5', '#66BB6A', '#FFA726'],
hoverBackgroundColor: ['#64B5F6', '#81C784', '#FFB74D']
}
]
},
chartOptions: this.isDarkTheme() ? this.getDarkTheme() : this.getLightTheme()
};
},
methods: {
isDarkTheme() {
return this.$appState.darkTheme === true;
},
getLightTheme() {
return {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
}
};
},
getDarkTheme() {
return {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
}
};
}
},
components: {
PieChartDoc: PieChartDoc
}
};
</script>

93
pages/chart/PieChartDoc.vue Executable file
View File

@ -0,0 +1,93 @@
<template>
<AppDoc name="ChartDemo" :sources="sources" :dependencies="{ 'chart.js': '3.3.2' }" component="Chart" github="chart/PieChartDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Chart type="pie" :data="chartData" :options="lightOptions" />
</div>
</template>
<script>
export default {
data() {
return {
chartData: {
labels: ['A','B','C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: ["#42A5F5","#66BB6A","#FFA726"],
hoverBackgroundColor: ["#64B5F6","#81C784","#FFB74D"]
}
]
},
lightOptions: {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
}
}
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Chart type="pie" :data="chartData" :options="lightOptions" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const chartData = ref({
labels: ['A','B','C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: ["#42A5F5","#66BB6A","#FFA726"],
hoverBackgroundColor: ["#64B5F6","#81C784","#FFB74D"]
}
]
});
const lightOptions = ref({
plugins: {
legend: {
labels: {
color: '#495057'
}
}
}
});
return { chartData, lightOptions }
}
}
<\\/script>
`
}
}
};
}
};
</script>

View File

@ -0,0 +1,97 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Polar Area Chart</h1>
<p>Polar area charts are similar to pie charts, but each segment has the same angle - the radius of the segment differs depending on the value.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card flex justify-content-center">
<Chart type="polarArea" :data="chartData" :options="chartOptions" style="width: 40%" />
</div>
</div>
<PolarAreaChartDoc />
</div>
</template>
<script>
import PolarAreaChartDoc from './PolarAreaChartDoc';
import EventBus from '@/layouts/AppEventBus';
export default {
themeChangeListener: null,
mounted() {
this.themeChangeListener = (event) => {
if (event.dark) this.chartOptions = this.getDarkTheme();
else this.chartOptions = this.getLightTheme();
};
EventBus.on('theme-change', this.themeChangeListener);
},
beforeUnmount() {
EventBus.off('change-theme', this.themeChangeListener);
},
data() {
return {
chartData: {
datasets: [
{
data: [11, 16, 7, 3, 14],
backgroundColor: ['#42A5F5', '#66BB6A', '#FFA726', '#26C6DA', '#7E57C2'],
label: 'My dataset'
}
],
labels: ['Red', 'Green', 'Yellow', 'Grey', 'Blue']
},
chartOptions: this.isDarkTheme() ? this.getDarkTheme() : this.getLightTheme()
};
},
methods: {
isDarkTheme() {
return this.$appState.darkTheme === true;
},
getLightTheme() {
return {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
r: {
grid: {
color: '#ebedef'
}
}
}
};
},
getDarkTheme() {
return {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
},
scales: {
r: {
grid: {
color: 'rgba(255,255,255,0.2)'
}
}
}
};
}
},
components: {
PolarAreaChartDoc: PolarAreaChartDoc
}
};
</script>

105
pages/chart/PolarAreaChartDoc.vue Executable file
View File

@ -0,0 +1,105 @@
<template>
<AppDoc name="ChartDemo" :sources="sources" :dependencies="{ 'chart.js': '3.3.2' }" component="Chart" github="chart/PolarAreaChartDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Chart type="polarArea" :data="chartData" :options="chartOptions" />
</div>
</template>
<script>
export default {
data() {
return {
chartData: {
datasets: [{
data: [11,16,7,3,14],
backgroundColor: ["#42A5F5","#66BB6A","#FFA726","#26C6DA","#7E57C2"],
label: 'My dataset'
}],
labels: ["Red","Green","Yellow","Grey","Blue"]
},
chartOptions: {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
r: {
grid: {
color: '#ebedef'
}
}
}
}
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Chart type="polarArea" :data="chartData" :options="chartOptions" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const chartData = ref({
datasets: [{
data: [11,16,7,3,14],
backgroundColor: ["#42A5F5","#66BB6A","#FFA726","#26C6DA","#7E57C2"],
label: 'My dataset'
}],
labels: ["Red","Green","Yellow","Grey","Blue"]
});
const chartOptions = ref(
{
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
r: {
grid: {
color: '#ebedef'
}
}
}
}
);
return { chartData, chartOptions }
}
}
<\\/script>
`
}
}
};
}
};
</script>

124
pages/chart/RadarChartDemo.vue Executable file
View File

@ -0,0 +1,124 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Radar Chart</h1>
<p>A radar chart is a graphical method of displaying multivariate data in the form of a two-dimensional chart of three or more quantitative variables represented on axes starting from the same point.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card flex justify-content-center">
<Chart type="radar" :data="chartData" :options="chartOptions" style="width: 40%" />
</div>
</div>
<RadarChartDoc />
</div>
</template>
<script>
import RadarChartDoc from './RadarChartDoc';
import EventBus from '@/layouts/AppEventBus';
export default {
themeChangeListener: null,
mounted() {
this.themeChangeListener = (event) => {
if (event.dark) this.chartOptions = this.getDarkTheme();
else this.chartOptions = this.getLightTheme();
};
EventBus.on('theme-change', this.themeChangeListener);
},
beforeUnmount() {
EventBus.off('change-theme', this.themeChangeListener);
},
data() {
return {
chartData: {
labels: ['Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(179,181,198,0.2)',
borderColor: 'rgba(179,181,198,1)',
pointBackgroundColor: 'rgba(179,181,198,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(179,181,198,1)',
data: [65, 59, 90, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: 'rgba(255,99,132,0.2)',
borderColor: 'rgba(255,99,132,1)',
pointBackgroundColor: 'rgba(255,99,132,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(255,99,132,1)',
data: [28, 48, 40, 19, 96, 27, 100]
}
]
},
chartOptions: this.isDarkTheme() ? this.getDarkTheme() : this.getLightTheme()
};
},
methods: {
isDarkTheme() {
return this.$appState.darkTheme === true;
},
getLightTheme() {
return {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
r: {
pointLabels: {
color: '#495057'
},
grid: {
color: '#ebedef'
},
angleLines: {
color: '#ebedef'
}
}
}
};
},
getDarkTheme() {
return {
plugins: {
legend: {
labels: {
color: '#ebedef'
}
}
},
scales: {
r: {
pointLabels: {
color: '#ebedef'
},
grid: {
color: 'rgba(255,255,255,0.2)'
},
angleLines: {
color: 'rgba(255,255,255,0.2)'
}
}
}
};
}
},
components: {
RadarChartDoc: RadarChartDoc
}
};
</script>

149
pages/chart/RadarChartDoc.vue Executable file
View File

@ -0,0 +1,149 @@
<template>
<AppDoc name="ChartDemo" :sources="sources" :dependencies="{ 'chart.js': '3.3.2' }" component="Chart" github="chart/RadarChartDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Chart type="radar" :data="chartData" :options="chartOptions" />
</div>
</template>
<script>
export default {
data() {
return {
chartData: {
labels: ['Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(179,181,198,0.2)',
borderColor: 'rgba(179,181,198,1)',
pointBackgroundColor: 'rgba(179,181,198,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(179,181,198,1)',
data: [65, 59, 90, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: 'rgba(255,99,132,0.2)',
borderColor: 'rgba(255,99,132,1)',
pointBackgroundColor: 'rgba(255,99,132,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(255,99,132,1)',
data: [28, 48, 40, 19, 96, 27, 100]
}
]
},
chartOption: {
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
r: {
pointLabels: {
color: '#495057',
},
grid: {
color: '#ebedef',
},
angleLines: {
color: '#ebedef'
}
}
}
}
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Chart type="radar" :data="chartData" :options="chartOptions" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const chartData = ref({
labels: ['Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(179,181,198,0.2)',
borderColor: 'rgba(179,181,198,1)',
pointBackgroundColor: 'rgba(179,181,198,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(179,181,198,1)',
data: [65, 59, 90, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: 'rgba(255,99,132,0.2)',
borderColor: 'rgba(255,99,132,1)',
pointBackgroundColor: 'rgba(255,99,132,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(255,99,132,1)',
data: [28, 48, 40, 19, 96, 27, 100]
}
]
});
const chartOptions = ref({
plugins: {
legend: {
labels: {
color: '#495057'
}
}
},
scales: {
r: {
pointLabels: {
color: '#495057',
},
grid: {
color: '#ebedef',
},
angleLines: {
color: '#ebedef'
}
}
}
});
return { chartData, chartOptions }
}
}
<\\/script>
`
}
}
};
}
};
</script>

15
pages/chart/index.vue Executable file
View File

@ -0,0 +1,15 @@
<template>
<div>
<ChartDoc />
</div>
</template>
<script>
import ChartDoc from './ChartDoc';
export default {
components: {
ChartDoc: ChartDoc
}
};
</script>

429
pages/checkbox/CheckboxDoc.vue Executable file
View File

@ -0,0 +1,429 @@
<template>
<AppDoc name="CheckboxDemo" :sources="sources" github="checkbox/CheckboxDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Checkbox from 'primevue/checkbox';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/checkbox/checkbox.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Checkbox can either be used in multiple selection with other checkboxes or as a single checkbox to provide a boolean value.</p>
<pre v-code><code>
&lt;Checkbox v-model="checked" :binary="true" /&gt;
</code></pre>
<h5>Multiple Values</h5>
<p>Multiple mode is enabled by default, v-model property refers to an array to bind the selected values.</p>
<pre v-code><code>
&lt;Checkbox name="city" value="Chicago" v-model="cities" /&gt;
&lt;Checkbox name="city" value="Los Angeles" v-model="cities" /&gt;
&lt;Checkbox name="city" value="New York" v-model="cities" /&gt;
&lt;Checkbox name="city" value="San Francisco" v-model="cities" /&gt;
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
cities: []
}
}
}
</code></pre>
<p>As v-model is two-way binding enabled, prepopulating the model array with values is enough to display the related checkboxes as checked by default.</p>
<h5>Properties</h5>
<p>Any valid attribute is passed to the root element implicitly, extended properties are as follows;</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>value</td>
<td>any</td>
<td>null</td>
<td>Value of the checkbox.</td>
</tr>
<tr>
<td>modelValue</td>
<td>any</td>
<td>null</td>
<td>Value binding of the checkbox.</td>
</tr>
<tr>
<td>name</td>
<td>string</td>
<td>null</td>
<td>Name of the input element.</td>
</tr>
<tr>
<td>binary</td>
<td>boolean</td>
<td>false</td>
<td>Allows to select a boolean value instead of multiple values.</td>
</tr>
<tr>
<td>trueValue</td>
<td>any</td>
<td>null</td>
<td>Value in checked state.</td>
</tr>
<tr>
<td>falseValue</td>
<td>any</td>
<td>null</td>
<td>Value in unchecked state.</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>false</td>
<td>When present, it specifies that the element should be disabled.</td>
</tr>
<tr>
<td>readonly</td>
<td>boolean</td>
<td>false</td>
<td>When present, it specifies that an input field is read-only.</td>
</tr>
<tr>
<td>required</td>
<td>boolean</td>
<td>false</td>
<td>When present, it specifies that the element is required.</td>
</tr>
<tr>
<td>tabindex</td>
<td>number</td>
<td>null</td>
<td>Index of the element in tabbing order.</td>
</tr>
<tr>
<td>inputId</td>
<td>string</td>
<td>null</td>
<td>Identifier of the underlying input element.</td>
</tr>
<tr>
<td>inputClass</td>
<td>any</td>
<td>null</td>
<td>Style class of the input field.</td>
</tr>
<tr>
<td>inputStyle</td>
<td>any</td>
<td>null</td>
<td>Inline style of the input field.</td>
</tr>
<tr>
<td>inputProps</td>
<td>object</td>
<td>null</td>
<td>Uses to pass all properties of the HTMLInputElement to the focusable input element inside the component.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<p>In addition to the following events, any other valid events such as focus and blur are passed implicitly.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>click</td>
<td>event: Browser event</td>
<td>Callback to invoke on value click.</td>
</tr>
<tr>
<td>change</td>
<td>event: Browser event</td>
<td>Callback to invoke on value change.</td>
</tr>
<tr>
<td>input</td>
<td>value: New value</td>
<td>Callback to invoke on value change.</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-checkbox</td>
<td>Container element</td>
</tr>
<tr>
<td>p-checkbox-box</td>
<td>Container of icon.</td>
</tr>
<tr>
<td>p-checkbox-icon</td>
<td>Icon element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Accessibility</h5>
<h6>Screen Reader</h6>
<p>
Checkbox component uses a hidden native checkbox element internally that is only visible to screen readers. Value to describe the component can either be provided via <i>label</i> tag combined with <i>id</i> prop or using
<i>aria-labelledby</i>, <i>aria-label</i> props.
</p>
<pre v-code><code>
&lt;label for="chkbox1"&gt;Remember Me&lt;/label&gt;
&lt;Checkbox inputId="chkbox1" /&gt;
&lt;span id="chkbox2"&gt;Remember Me&lt;/span&gt;
&lt;Checkbox aria-labelledby="chkbox2" /&gt;
&lt;Checkbox aria-label="Remember Me" /&gt;
</code></pre>
<h6>Keyboard Support</h6>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Key</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td><i>tab</i></td>
<td>Moves focus to the checkbox.</td>
</tr>
<tr>
<td><i>space</i></td>
<td>Toggles the checked state.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<div class="field-checkbox">
<Checkbox inputId="binary" v-model="checked" :binary="true" />
<label for="binary">{{checked}}</label>
</div>
<h5>Multiple</h5>
<div class="field-checkbox">
<Checkbox inputId="city1" name="city" value="Chicago" v-model="cities" />
<label for="city1">Chicago</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city2" name="city" value="Los Angeles" v-model="cities" />
<label for="city2">Los Angeles</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city3" name="city" value="New York" v-model="cities" />
<label for="city3">New York</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city4" name="city" value="San Francisco" v-model="cities" />
<label for="city4">San Francisco</label>
</div>
<h5>Dynamic Values, Preselection, Value Binding and Disabled Option</h5>
<div v-for="category of categories" :key="category.key" class="field-checkbox">
<Checkbox :inputId="category.key" name="category" :value="category.name" v-model="selectedCategories" :disabled="category.key === 'R'"/>
<label :for="category.key">{{category.name}}</label>
</div>
</div>
</template>
<script>
export default {
data() {
return {
checked: false,
cities: [],
categories: [{name: 'Accounting', key: 'A'}, {name: 'Marketing', key: 'M'}, {name: 'Production', key: 'P'}, {name: 'Research', key: 'R'}],
selectedCategories: []
}
},
created() {
this.selectedCategories = this.categories.slice(1,3);
}
}
<\\/script>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<div class="field-checkbox">
<Checkbox inputId="binary" v-model="checked" :binary="true" />
<label for="binary">{{checked}}</label>
</div>
<h5>Multiple</h5>
<div class="field-checkbox">
<Checkbox inputId="city1" name="city" value="Chicago" v-model="cities" />
<label for="city1">Chicago</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city2" name="city" value="Los Angeles" v-model="cities" />
<label for="city2">Los Angeles</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city3" name="city" value="New York" v-model="cities" />
<label for="city3">New York</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city4" name="city" value="San Francisco" v-model="cities" />
<label for="city4">San Francisco</label>
</div>
<h5>Dynamic Values, Preselection, Value Binding and Disabled Option</h5>
<div v-for="category of categories" :key="category.key" class="field-checkbox">
<Checkbox :inputId="category.key" name="category" :value="category.name" v-model="selectedCategories" :disabled="category.key === 'R'"/>
<label :for="category.key">{{category.name}}</label>
</div>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const checked = ref(false);
const cities = ref([]);
const categories = ref([
{name: 'Accounting', key: 'A'},
{name: 'Marketing', key: 'M'},
{name: 'Production', key: 'P'},
{name: 'Research', key: 'R'}
]);
const selectedCategories = ref(categories.value.slice(1,3));
return { checked, cities, categories, selectedCategories }
}
}
<\\/script>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/checkbox/checkbox.min.js"><\\/script>`,
content: `<div id="app">
<h5>Basic</h5>
<div class="field-checkbox">
<p-checkbox inputId="binary" v-model="checked" :binary="true"></p-checkbox>
<label for="binary">{{checked}}</label>
</div>
<h5>Multiple</h5>
<div class="field-checkbox">
<p-checkbox inputId="city1" name="city" value="Chicago" v-model="cities"></p-checkbox>
<label for="city1">Chicago</label>
</div>
<div class="field-checkbox">
<p-checkbox inputId="city2" name="city" value="Los Angeles" v-model="cities"></p-checkbox>
<label for="city2">Los Angeles</label>
</div>
<div class="field-checkbox">
<p-checkbox inputId="city3" name="city" value="New York" v-model="cities"></p-checkbox>
<label for="city3">New York</label>
</div>
<div class="field-checkbox">
<p-checkbox inputId="city4" name="city" value="San Francisco" v-model="cities"></p-checkbox>
<label for="city4">San Francisco</label>
</div>
<h5>Dynamic Values, Preselection, Value Binding and Disabled Option</h5>
<div v-for="category of categories" :key="category.key" class="field-checkbox">
<p-checkbox :inputId="category.key" name="category" :value="category.name" v-model="selectedCategories" :disabled="category.key === 'R'"></p-checkbox>
<label :for="category.key">{{category.name}}</label>
</div>
</div>
<script type="module">
const { createApp, ref } = Vue;
const App = {
setup() {
const checked = ref(false);
const cities = ref([]);
const categories = ref([
{name: 'Accounting', key: 'A'},
{name: 'Marketing', key: 'M'},
{name: 'Production', key: 'P'},
{name: 'Research', key: 'R'}
]);
const selectedCategories = ref(categories.value.slice(1,3));
return { checked, cities, categories, selectedCategories }
},
components: {
"p-checkbox": primevue.checkbox
}
};
createApp(App).use(primevue.config.default).mount('#app');
<\\/script>
`
}
}
};
}
};
</script>

73
pages/checkbox/index.vue Executable file
View File

@ -0,0 +1,73 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Checkbox</h1>
<p>Checkbox is an extension to standard checkbox element with theming.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<div class="field-checkbox">
<Checkbox inputId="binary" v-model="checked" :binary="true" />
<label for="binary">Remember Me</label>
</div>
<h5>Multiple</h5>
<div class="field-checkbox">
<Checkbox inputId="city1" name="city" value="Chicago" v-model="cities" />
<label for="city1">Chicago</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city2" name="city" value="Los Angeles" v-model="cities" />
<label for="city2">Los Angeles</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city3" name="city" value="New York" v-model="cities" />
<label for="city3">New York</label>
</div>
<div class="field-checkbox">
<Checkbox inputId="city4" name="city" value="San Francisco" v-model="cities" />
<label for="city4">San Francisco</label>
</div>
<h5>Dynamic Values, Preselection, Value Binding and Disabled Option</h5>
<div v-for="category of categories" :key="category.key" class="field-checkbox">
<Checkbox :inputId="category.key" name="category" :value="category.name" v-model="selectedCategories" :disabled="category.key === 'R'" />
<label :for="category.key">{{ category.name }}</label>
</div>
</div>
</div>
<CheckboxDoc />
</div>
</template>
<script>
import CheckboxDoc from './CheckboxDoc';
export default {
data() {
return {
checked: false,
cities: [],
categories: [
{ name: 'Accounting', key: 'A' },
{ name: 'Marketing', key: 'M' },
{ name: 'Production', key: 'P' },
{ name: 'Research', key: 'R' }
],
selectedCategories: []
};
},
created() {
this.selectedCategories = this.categories.slice(1, 3);
},
components: {
CheckboxDoc: CheckboxDoc
}
};
</script>

312
pages/chip/ChipDoc.vue Normal file
View File

@ -0,0 +1,312 @@
<template>
<AppDoc name="ChipDemo" :sources="sources" github="chip/ChipDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Chip from 'primevue/chip';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/chip/chip.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Chip can display labels, icons and images.</p>
<pre v-code><code>
&lt;Chip label="Text Only" /&gt;
&lt;Chip label="Text with icon" icon="pi pi-check" /&gt;
&lt;Chip label="Text with image" image="user.png" /&gt;
</code></pre>
<h5>Removable</h5>
<p>Setting <i>removable</i> property displays an icon to close the chip, the optional <i>remove</i> event is available to get notified when a chip is hidden.</p>
<pre v-code><code>
&lt;Chip label="Text" removable /&gt;
</code></pre>
<h5>Templating</h5>
<p>Content can easily be customized with the default slot instead of using the built-in modes.</p>
<pre v-code><code>
&lt;Chip&gt;
Content
&lt;/Chip&gt;
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>label</td>
<td>string</td>
<td>null</td>
<td>Defines the text to display.</td>
</tr>
<tr>
<td>icon</td>
<td>string</td>
<td>null</td>
<td>Defines the icon to display.</td>
</tr>
<tr>
<td>image</td>
<td>string</td>
<td>null</td>
<td>Defines the image to display.</td>
</tr>
<tr>
<td>removable</td>
<td>boolean</td>
<td>false</td>
<td>Whether to display a remove icon.</td>
</tr>
<tr>
<td>removeIconClass</td>
<td>string</td>
<td>pi pi-times-circle</td>
<td>Icon of the remove element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>remove</td>
<td>event: Browser event</td>
<td>Callback to invoke when a chip is removed.</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-chip</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-chip-image</td>
<td>Container element in image mode.</td>
</tr>
<tr>
<td>p-chip-text</td>
<td>Text of the chip.</td>
</tr>
<tr>
<td>p-chip-remove-icon</td>
<td>Remove icon.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Action" class="mr-2 mb-2" />
<Chip label="Comedy" class="mr-2 mb-2" />
<Chip label="Mystery" class="mr-2 mb-2" />
<Chip label="Thriller" class="mb-2" removable />
</div>
<h5>Icon</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Apple" icon="pi pi-apple" class="mr-2 mb-2" />
<Chip label="Facebook" icon="pi pi-facebook" class="mr-2 mb-2" />
<Chip label="Google" icon="pi pi-google" class="mr-2 mb-2" />
<Chip label="Microsoft" icon="pi pi-microsoft" class="mb-2" removable />
</div>
<h5>Image</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Amy Elsner" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2" />
<Chip label="Asiya Javayant" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2" />
<Chip label="Onyama Limba" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2" />
<Chip label="Xuxue Feng" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mb-2" removable />
</div>
<h5>Styling</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Action" class="mr-2 mb-2 custom-chip" />
<Chip label="Apple" icon="pi pi-apple" class="mr-2 mb-2 custom-chip" />
<Chip label="Onyama Limba" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2 custom-chip" />
<Chip label="Xuxue Feng" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="custom-chip mb-2" removable />
</div>
</div>
</template>
<script>
export default {
}
<\\/script>
<style lang="scss" scoped>
.p-chip.custom-chip {
background: var(--primary-color);
color: var(--primary-color-text);
}
</style>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Action" class="mr-2 mb-2" />
<Chip label="Comedy" class="mr-2 mb-2" />
<Chip label="Mystery" class="mr-2 mb-2" />
<Chip label="Thriller" class="mb-2" removable />
</div>
<h5>Icon</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Apple" icon="pi pi-apple" class="mr-2 mb-2" />
<Chip label="Facebook" icon="pi pi-facebook" class="mr-2 mb-2" />
<Chip label="Google" icon="pi pi-google" class="mr-2 mb-2" />
<Chip label="Microsoft" icon="pi pi-microsoft" class="mb-2" removable />
</div>
<h5>Image</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Amy Elsner" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2" />
<Chip label="Asiya Javayant" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2" />
<Chip label="Onyama Limba" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2" />
<Chip label="Xuxue Feng" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mb-2" removable />
</div>
<h5>Styling</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<Chip label="Action" class="mr-2 mb-2 custom-chip" />
<Chip label="Apple" icon="pi pi-apple" class="mr-2 mb-2 custom-chip" />
<Chip label="Onyama Limba" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2 custom-chip" />
<Chip label="Xuxue Feng" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="custom-chip mb-2" removable />
</div>
</div>
</template>
<script>
export default {
}
<\\/script>
<style lang="scss" scoped>
.p-chip.custom-chip {
background: var(--primary-color);
color: var(--primary-color-text);
}
</style>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/chip/chip.min.js"><\\/script>`,
content: `<div id="app">
<h5>Basic</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<p-chip label="Action" class="mr-2 mb-2"></p-chip>
<p-chip label="Comedy" class="mr-2 mb-2"></p-chip>
<p-chip label="Mystery" class="mr-2 mb-2"></p-chip>
<p-chip label="Thriller" class="mb-2" removable></p-chip>
</div>
<h5>Icon</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<p-chip label="Apple" icon="pi pi-apple" class="mr-2 mb-2"></p-chip>
<p-chip label="Facebook" icon="pi pi-facebook" class="mr-2 mb-2"></p-chip>
<p-chip label="Google" icon="pi pi-google" class="mr-2 mb-2"></p-chip>
<p-chip label="Microsoft" icon="pi pi-microsoft" class="mb-2" removable></p-chip>
</div>
<h5>Image</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<p-chip label="Amy Elsner" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2"></p-chip>
<p-chip label="Asiya Javayant" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2"></p-chip>
<p-chip label="Onyama Limba" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2"></p-chip>
<p-chip label="Xuxue Feng" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mb-2" removable></p-chip>
</div>
<h5>Styling</h5>
<div class="flex align-items-center flex-column sm:flex-row">
<p-chip label="Action" class="mr-2 mb-2 custom-chip"></p-chip>
<p-chip label="Apple" icon="pi pi-apple" class="mr-2 mb-2 custom-chip"></p-chip>
<p-chip label="Onyama Limba" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="mr-2 mb-2 custom-chip"></p-chip>
<p-chip label="Xuxue Feng" image="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" class="custom-chip mb-2" removable></p-chip>
</div>
</div>
<script type="module">
const { createApp } = Vue;
const App = {
components: {
"p-chip": primevue.chip
}
};
createApp(App).mount('#app');
<\\/script>
<style>
.p-chip.custom-chip {
background: var(--primary-color);
color: var(--primary-color-text);
}
</style>
`
}
}
};
}
};
</script>

66
pages/chip/index.vue Normal file
View File

@ -0,0 +1,66 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Chip</h1>
<p>Chip represents entities using icons, labels and images.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<div class="flex align-items-center">
<Chip label="Action" class="mr-2" />
<Chip label="Comedy" class="mr-2" />
<Chip label="Mystery" class="mr-2" />
<Chip label="Thriller" removable />
</div>
<h5>Icon</h5>
<div class="flex align-items-center">
<Chip label="Apple" icon="pi pi-apple" class="mr-2" />
<Chip label="Facebook" icon="pi pi-facebook" class="mr-2" />
<Chip label="Google" icon="pi pi-google" class="mr-2" />
<Chip label="Microsoft" icon="pi pi-microsoft" removable />
</div>
<h5>Image</h5>
<div class="flex align-items-center">
<Chip label="Amy Elsner" image="demo/images/avatar/amyelsner.png" class="mr-2" />
<Chip label="Asiya Javayant" image="demo/images/avatar/asiyajavayant.png" class="mr-2" />
<Chip label="Onyama Limba" image="demo/images/avatar/onyamalimba.png" class="mr-2" />
<Chip label="Xuxue Feng" image="demo/images/avatar/xuxuefeng.png" removable />
</div>
<h5>Styling</h5>
<div class="flex align-items-center">
<Chip label="Action" class="mr-2 custom-chip" />
<Chip label="Apple" icon="pi pi-apple" class="mr-2 custom-chip" />
<Chip label="Onyama Limba" image="demo/images/avatar/onyamalimba.png" class="mr-2 custom-chip" />
<Chip label="Xuxue Feng" image="demo/images/avatar/xuxuefeng.png" class="custom-chip" removable />
</div>
</div>
</div>
<ChipDoc />
</div>
</template>
<script>
import ChipDoc from './ChipDoc';
export default {
components: {
ChipDoc: ChipDoc
}
};
</script>
<style lang="scss" scoped>
.p-chip.custom-chip {
background: var(--primary-color);
color: var(--primary-color-text);
}
</style>

420
pages/chips/ChipsDoc.vue Executable file
View File

@ -0,0 +1,420 @@
<template>
<AppDoc name="ChipsDemo" :sources="sources" github="chips/ChipsDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Chips from 'primevue/chips';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/chips/chips.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>An array as the value can be bound using the standard v-model directive.</p>
<pre v-code><code>
&lt;Chips v-model="value" /&gt;
</code></pre>
<h5>Custom Content</h5>
<p>A chip is customized using the <i>chip</i> template where the chip value is passed to the slotProps with the value property.</p>
<pre v-code><code><template v-pre>
&lt;Chips v-model="value"&gt;
&lt;template #chip="slotProps"&gt;
&lt;div&gt;
&lt;span&gt;{{slotProps.value}} - (active) &lt;/span&gt;
&lt;i class="pi pi-user-plus" style="font-size: 14px"&gt;&lt;/i&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/Chips&gt;
</template>
</code></pre>
<h5>Properties</h5>
<p>Any property such as name and placeholder are passed to the underlying input element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>modelValue</td>
<td>array</td>
<td>null</td>
<td>Value of the component.</td>
</tr>
<tr>
<td>max</td>
<td>number</td>
<td>null</td>
<td>Maximum number of entries allowed.</td>
</tr>
<tr>
<td>separator</td>
<td>string</td>
<td>null</td>
<td>Separator char to add an item when pressed in addition to the enter key. Currently only possible value is ","</td>
</tr>
<tr>
<td>addOnBlur</td>
<td>boolean</td>
<td>false</td>
<td>Whether to add an item when the input loses focus.</td>
</tr>
<tr>
<td>allowDuplicate</td>
<td>boolean</td>
<td>true</td>
<td>Whether to allow duplicate values or not.</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>false</td>
<td>When present, it specifies that the element should be disabled.</td>
</tr>
<tr>
<td>placeholder</td>
<td>string</td>
<td>null</td>
<td>Placeholder text for the input.</td>
</tr>
<tr>
<td>inputId</td>
<td>string</td>
<td>null</td>
<td>Style class of the component input field.</td>
</tr>
<tr>
<td>inputClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the input field.</td>
</tr>
<tr>
<td>inputStyle</td>
<td>any</td>
<td>null</td>
<td>Inline style of the input field.</td>
</tr>
<tr>
<td>inputProps</td>
<td>object</td>
<td>null</td>
<td>Uses to pass all properties of the HTMLInputElement to the focusable input element inside the component.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<p>Any valid event such as focus, blur and input are passed to the underlying input element. Following are the additional events to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>add</td>
<td>
originalEvent: Browser event <br />
value: Added item value
</td>
<td>Callback to invoke when a chip is added.</td>
</tr>
<tr>
<td>remove</td>
<td>
originalEvent: Browser event <br />
value: Removed item value
</td>
<td>Callback to invoke when a chip is removed.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>chip</td>
<td>value: Value of the component</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-chips</td>
<td>Container element</td>
</tr>
<tr>
<td>p-chips-token</td>
<td>Chip element container.</td>
</tr>
<tr>
<td>p-chips-token-icon</td>
<td>Icon of a chip.</td>
</tr>
<tr>
<td>p-chips-token-label</td>
<td>label of a chip.</td>
</tr>
<tr>
<td>p-chips-input-token</td>
<td>Container of input element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Accessibility</h5>
<h6>Screen Reader</h6>
<p>
Value to describe the component can either be provided via <i>label</i> tag combined with <i>inputId</i> prop or using <i>aria-labelledby</i>, <i>aria-label</i> props. Chip list uses <i>listbox</i> role with <i>aria-orientation</i> set to
horizontal whereas each chip has the <i>option</i> role with <i>aria-label</i> set to the label of the chip.
</p>
<pre v-code><code>
&lt;label for="chips1"&gt;Tags&lt;/label&gt;
&lt;Chips inputId="chips1" /&gt;
&lt;span id="chips2"&gt;Tags&lt;/span&gt;
&lt;Chips aria-labelledby="chips2" /&gt;
&lt;Chips aria-label="Tags" /&gt;
</code></pre>
<h6>Input Field Keyboard Support</h6>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Key</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td><i>tab</i></td>
<td>Moves focus to the input element</td>
</tr>
<tr>
<td><i>enter</i></td>
<td>Adds a new chips using the input field value.</td>
</tr>
<tr>
<td><i>backspace</i></td>
<td>Deletes the previous chip if the input field is empty.</td>
</tr>
<tr>
<td><i>left arrow</i></td>
<td>Moves focus to the previous chip if available and input field is empty.</td>
</tr>
</tbody>
</table>
</div>
<h6>Chip Keyboard Support</h6>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Key</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td><i>left arrow</i></td>
<td>Moves focus to the previous chip if available.</td>
</tr>
<tr>
<td><i>right arrow</i></td>
<td>Moves focus to the next chip, if there is none then input field receives the focus.</td>
</tr>
<tr>
<td><i>backspace</i></td>
<td>Deletes the chips and adds focus to the input field.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div class="p-fluid">
<div class="card">
<h5>Basic</h5>
<Chips v-model="value1" />
<h5>Comma Separator</h5>
<Chips v-model="value2" separator="," />
<h5>Template</h5>
<Chips v-model="value3">
<template #chip="slotProps">
<div>
<span>{{slotProps.value}} - (active) </span>
<i class="pi pi-user-plus" style="font-size: 14px"></i>
</div>
</template>
</Chips>
</div>
</div>
</template>
<script>
export default {
data() {
return {
value1: null,
value2: null,
value3: null
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div class="p-fluid">
<div class="card">
<h5>Basic</h5>
<Chips v-model="value1" />
<h5>Comma Separator</h5>
<Chips v-model="value2" separator="," />
<h5>Template</h5>
<Chips v-model="value3">
<template #chip="slotProps">
<div>
<span>{{slotProps.value}} - (active) </span>
<i class="pi pi-user-plus" style="font-size: 14px"></i>
</div>
</template>
</Chips>
</div>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const value1 = ref();
const value2 = ref();
const value3 = ref();
return { value1, value2, value3 }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/chips/chips.min.js"><\\/script>`,
content: `<div id="app">
<div class="p-fluid">
<div class="card">
<h5>Basic</h5>
<p-chips v-model="value1"></p-chips>
<h5>Comma Separator</h5>
<p-chips v-model="value2" separator=","></p-chips>
<h5>Template</h5>
<p-chips v-model="value3">
<template #chip="slotProps">
<div>
<span>{{slotProps.value}} - (active) </span>
<i class="pi pi-user-plus" style="font-size: 14px"></i>
</div>
</template>
</p-chips>
</div>
</div>
</div>
<script type="module">
const { createApp, ref } = Vue;
const App = {
setup() {
const value1 = ref();
const value2 = ref();
const value3 = ref();
return { value1, value2, value3 }
},
components: {
"p-chips": primevue.chips
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

50
pages/chips/index.vue Executable file
View File

@ -0,0 +1,50 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Chips</h1>
<p>Chips is used to enter multiple values on an input field.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation p-fluid">
<div class="card">
<h5>Basic</h5>
<Chips v-model="value1" />
<h5>Comma Separator</h5>
<Chips v-model="value2" separator="," />
<h5>Template</h5>
<Chips v-model="value3">
<template #chip="slotProps">
<div>
<span>{{ slotProps.value }} - (active) </span>
<i class="pi pi-user-plus" style="font-size: 14px"></i>
</div>
</template>
</Chips>
</div>
</div>
<ChipsDoc />
</div>
</template>
<script>
import ChipsDoc from './ChipsDoc';
export default {
data() {
return {
value1: null,
value2: null,
value3: null
};
},
components: {
ChipsDoc: ChipsDoc
}
};
</script>

File diff suppressed because one or more lines are too long

57
pages/colorpicker/index.vue Executable file
View File

@ -0,0 +1,57 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>ColorPicker</h1>
<p>ColorPicker is an input component to select a color.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Inline</h5>
<ColorPicker v-model="color1" :inline="true" />
<h5>Overlay</h5>
<ColorPicker v-model="color2" />
</div>
<div class="card">
<h5>Wall Color</h5>
<div class="flex flex-column align-items-center md:flex-row md:align-items-start">
<ColorPicker v-model="color3" :inline="true" />
<div :style="wallStyle" class="mt-5 md:mt-0 md:ml-5 inline-flex">
<img alt="room" src="demo/images/interior.png" class="w-full md:auto" />
</div>
</div>
</div>
</div>
<ColorPickerDoc />
</div>
</template>
<script>
import ColorPickerDoc from './ColorPickerDoc';
export default {
data() {
return {
color1: null,
color2: '1976D2',
color3: '474747'
};
},
computed: {
wallStyle() {
return {
backgroundColor: '#' + this.color3
};
}
},
components: {
ColorPickerDoc: ColorPickerDoc
}
};
</script>

163
pages/colors/index.vue Normal file
View File

@ -0,0 +1,163 @@
<template>
<div>
<div class="content-section documentation">
<h1>Colors</h1>
<p>Each PrimeVue theme exports its own color palette.</p>
<h5>Getting Started</h5>
<p>Colors are exported as CSS variables and used with the standard <i>var</i> syntax such as <i>var(--text-color)</i>.</p>
<pre v-code><code>
&lt;span :style="{color:var(--text-color)}"&gt;&lt;/span&gt;
</code></pre>
<h5>General Colors</h5>
<p>These are common variables used throughout the theme.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Variable</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><i>--text-color</i></td>
<td>Font text color.</td>
</tr>
<tr>
<td><i>--text-color-secondary</i></td>
<td>Muted font text color with a secondary level.</td>
</tr>
<tr>
<td><i>--primary-color</i></td>
<td>Primary color of the theme.</td>
</tr>
<tr>
<td><i>--primary-color-text</i></td>
<td>Text color when background is primary color.</td>
</tr>
<tr>
<td><i>--font-family</i></td>
<td>Font family of the theme.</td>
</tr>
<tr>
<td><i>--inline-spacing</i></td>
<td>Spacing between to adjacent items.</td>
</tr>
<tr>
<td><i>--border-radius</i></td>
<td>Common border radius of elements.</td>
</tr>
<tr>
<td><i>--focus-ring</i></td>
<td>Box shadow of a focused element.</td>
</tr>
<tr>
<td><i>--mask-bg</i></td>
<td>Background of an overlay mask.</td>
</tr>
</tbody>
</table>
</div>
<h5>Color Palette</h5>
<p>A palette consists of 9 colors where each color provides tints/shades from 50 to 900.</p>
<pre v-code><code>
&lt;div :style="{backgroundColor:var(--blue-500)}"&gt;&lt;/div&gt;
</code></pre>
<div class="card">
<div class="flex flex-wrap">
<div v-for="color of colors" :key="color" class="color-stack mr-6 mb-6">
<template v-for="shade of shades" :key="shade">
<div v-if="shade !== 0" class="color-box" :style="{ backgroundColor: `var(--${color}-${shade})`, color: shade > 500 ? '#fff' : '#000' }">{{ color }}-{{ shade }}</div>
</template>
</div>
</div>
</div>
<h5>Surfaces</h5>
<p>In addition, a theme brings a special palette called surfaces that can be used as the base when designing the surface layers and separators.</p>
<div class="card">
<div class="color-stack">
<div v-for="shade in shades" :key="shade" class="color-box" :style="{ backgroundColor: `var(--surface-${shade})`, color: $appState.darkTheme ? '#fff' : shade > 500 ? '#fff' : '#000' }">surface-{{ shade }}</div>
</div>
</div>
<p>A theme also exports named surfaces for common use cases.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Variable</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><i>--surface-ground</i></td>
<td>Base ground color.</td>
</tr>
<tr>
<td><i>--surface-section</i></td>
<td>Color of a section on a ground surface.</td>
</tr>
<tr>
<td><i>--surface-card</i></td>
<td>Color of a surface used as a card.</td>
</tr>
<tr>
<td><i>--surface-overlay</i></td>
<td>Color of overlay surfaces.</td>
</tr>
<tr>
<td><i>--surface-border</i></td>
<td>Color of a divider.</td>
</tr>
<tr>
<td><i>--surface-hover</i></td>
<td>Color of an element in hover state.</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
colors: ['blue', 'green', 'yellow', 'cyan', 'pink', 'indigo', 'teal', 'orange', 'bluegray', 'purple', 'red', 'gray', 'primary'],
shades: [0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900]
};
}
};
</script>
<style lang="scss" scoped>
.color-stack {
display: flex;
flex-direction: column;
}
.color-box {
width: 2.5rem;
display: flex;
align-items: center;
padding: 1rem;
width: 250px;
font-weight: bold;
}
.sample-layout {
width: 375px;
}
</style>

View File

@ -0,0 +1,707 @@
<template>
<AppDoc name="ConfirmDialogDemo" :sources="sources" github="confirmdialog/ConfirmDialogDemo.vue">
<h5>ConfirmationService</h5>
<p>ConfirmDialog is controlled via the <i>ConfirmationService</i> that needs to be installed globally before the application instance is created.</p>
<pre v-code.script><code>
import {createApp} from 'vue';
import ConfirmationService from 'primevue/confirmationservice';
const app = createApp(App);
app.use(ConfirmationService);
</code></pre>
<h5>Import via Module</h5>
<pre v-code.script><code>
import ConfirmDialog from 'primevue/confirmdialog';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/confirmdialog/confirmdialog.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>
ConfirmDialog is displayed by calling the <i>require</i> method of the <i>$confirm</i> instance by passing the options to customize the Dialog. Suggested location of the Dialog is the main application component where it can be shared by
any component within the application.
</p>
<pre v-code><code>
&lt;ConfirmDialog&gt;&lt;/ConfirmDialog&gt;
&lt;Button @click="delete()" icon="pi pi-check" label="Confirm"&gt;&lt;/Button&gt;
</code></pre>
<pre v-code.script><code>
export default {
methods: {
delete() {
this.$confirm.require({
message: 'Are you sure you want to proceed?',
header: 'Confirmation',
icon: 'pi pi-exclamation-triangle',
accept: () => {
//callback to execute when user confirms the action
},
reject: () => {
//callback to execute when user rejects the action
}
});
},
}
}
</code></pre>
<h5>Composition API</h5>
<p>The service can be injected with the <i>useConfirm</i> function.</p>
<pre v-code.script><code>
import { defineComponent } from "vue";
import { useConfirm } from "primevue/useconfirm";
export default defineComponent({
setup() {
const confirm = useConfirm();
confirm.require({
message: 'Are you sure you want to proceed?',
header: 'Confirmation',
icon: 'pi pi-exclamation-triangle',
accept: () => {
//callback to execute when user confirms the action
},
reject: () => {
//callback to execute when user rejects the action
}
});
}
})
</code></pre>
<h5>Close Confirmation</h5>
<p>The dialog can also be hidden programmatically using the <i>close</i> method.</p>
<pre v-code.script><code>
export default {
methods: {
discard() {
this.$confirm.close();
}
}
}
</code></pre>
<h5>Templating</h5>
<p>Templating allows customizing the content where the message instance is available as the implicit variable.</p>
<pre v-code><code><template v-pre>
&lt;ConfirmPopup group="demo">
&lt;template #message="slotProps"&gt;
&lt;div class="flex p-4"&gt;
&lt;i :class="slotProps.message.icon" style="font-size: 1.5rem"&gt;&lt;/i&gt;
&lt;p class="pl-2"&gt;{{slotProps.message.message}}&lt;/p&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/ConfirmPopup&gt;
</template>
</code></pre>
<h5>Responsive</h5>
<p>
ConfirmDialog width can be adjusted per screen size with the <i>breakpoints</i> option. In example below, default width is set to 50vw and below 961px, width would be 75vw and finally below 641px width becomes 100%. The value of
<i>breakpoints</i> should be an object literal whose keys are the maximum screen sizes and values are the widths per screen.
</p>
<pre v-code><code>
&lt;ConfirmDialog :breakpoints="{'960px': '75vw', '640px': '100vw'}" :style="{width: '50vw'}"&gt;&lt;/ConfirmDialog&gt;
</code></pre>
<h5>Confirmation Options</h5>
<p>ConfirmDialog can be customized with various options listed here.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>message</td>
<td>string</td>
<td>null</td>
<td>Message of the confirmation.</td>
</tr>
<tr>
<td>group</td>
<td>string</td>
<td>null</td>
<td>Optional key to match the key of the confirmation, useful to target a specific confirm dialog instance.</td>
</tr>
<tr>
<td>icon</td>
<td>string</td>
<td>null</td>
<td>Icon to display next to the message.</td>
</tr>
<tr>
<td>header</td>
<td>string</td>
<td>null</td>
<td>Header text of the dialog.</td>
</tr>
<tr>
<td>position</td>
<td>string</td>
<td>center</td>
<td>Position of the dialog, options are "center", "top", "bottom", "left", "right", "topleft", "topright", "bottomleft" or "bottomright".</td>
</tr>
<tr>
<td>accept</td>
<td>Function</td>
<td>null</td>
<td>Callback to execute when action is confirmed.</td>
</tr>
<tr>
<td>reject</td>
<td>Function</td>
<td>null</td>
<td>Callback to execute when action is rejected.</td>
</tr>
<tr>
<td>acceptLabel</td>
<td>string</td>
<td>null</td>
<td>Label of the accept button. Defaults to PrimeVue <router-link to="/locale">Locale</router-link> configuration.</td>
</tr>
<tr>
<td>rejectLabel</td>
<td>string</td>
<td>null</td>
<td>Label of the reject button. Defaults to PrimeVue <router-link to="/locale">Locale</router-link> configuration.</td>
</tr>
<tr>
<td>acceptIcon</td>
<td>string</td>
<td>null</td>
<td>Icon of the accept button.</td>
</tr>
<tr>
<td>rejectIcon</td>
<td>string</td>
<td>null</td>
<td>Icon of the reject button.</td>
</tr>
<tr>
<td>acceptClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the accept button.</td>
</tr>
<tr>
<td>rejectClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the reject button.</td>
</tr>
<tr>
<td>blockScroll</td>
<td>boolean</td>
<td>true</td>
<td>Whether background scroll should be blocked when dialog is visible.</td>
</tr>
<tr>
<td>defaultFocus</td>
<td>string</td>
<td>accept</td>
<td>Element to receive the focus when the dialog gets visible, valid values are "accept" and "reject".</td>
</tr>
</tbody>
</table>
</div>
<h5>ConfirmationService</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>require</td>
<td>confirm: Confirmation Object</td>
<td>Displays the dialog using the confirmation object options.</td>
</tr>
<tr>
<td>close</td>
<td>-</td>
<td>Hides the dialog without invoking accept or reject callbacks.</td>
</tr>
</tbody>
</table>
</div>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>group</td>
<td>string</td>
<td>null</td>
<td>Optional key to match the key of the confirmation, useful to target a specific confirm dialog instance.</td>
</tr>
<tr>
<td>breakpoints</td>
<td>object</td>
<td>null</td>
<td>Object literal to define widths per screen size.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>message</td>
<td>-</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>ConfirmDialog inherits all the classes from the Dialog component, visit <router-link to="/dialog">dialog</router-link> for more information.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-confirm-dialog</td>
<td>Container element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Toast />
<ConfirmDialog></ConfirmDialog>
<ConfirmDialog group="templating">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{slotProps.message.message}}</p>
</div>
</template>
</ConfirmDialog>
<ConfirmDialog group="positionDialog"></ConfirmDialog>
<div class="card">
<h5>Basic</h5>
<Button @click="confirm1()" icon="pi pi-check" label="Confirm" class="mr-2"></Button>
<Button @click="confirm2()" icon="pi pi-times" label="Delete"></Button>
<h5>Templating</h5>
<Button @click="showTemplate()" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></Button>
<h5>Position</h5>
<div class="grid flex-column">
<div class="p-col">
<Button @click="confirmPosition('left')" icon="pi pi-arrow-right" label="Left" class="p-button-help mr-2"></Button>
<Button @click="confirmPosition('right')" icon="pi pi-arrow-left" label="Right" class="p-button-help"></Button>
</div>
<div class="p-col">
<Button @click="confirmPosition('topleft')" icon="pi pi-arrow-down-right" label="TopLeft" class="p-button-warning mr-2"></Button>
<Button @click="confirmPosition('top')" icon="pi pi-arrow-down" label="Top" class="p-button-warning mr-2"></Button>
<Button @click="confirmPosition('topright')" icon="pi pi-arrow-down-left" label="TopRight" class="p-button-warning"></Button>
</div>
<div class="p-col">
<Button @click="confirmPosition('bottomleft')" icon="pi pi-arrow-up-right" label="BottomLeft" class="p-button-success mr-2"></Button>
<Button @click="confirmPosition('bottom')" icon="pi pi-arrow-up" label="Bottom" class="p-button-success mr-2"></Button>
<Button @click="confirmPosition('bottomright')" icon="pi pi-arrow-up-left" label="BottomRight" class="p-button-success"></Button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
methods: {
confirm1() {
this.$confirm.require({
message: 'Are you sure you want to proceed?',
header: 'Confirmation',
icon: 'pi pi-exclamation-triangle',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
},
confirm2() {
this.$confirm.require({
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
},
confirmPosition(position) {
this.$confirm.require({
group: 'positionDialog',
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
position: position,
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
},
showTemplate() {
this.$confirm.require({
group: 'templating',
header: 'Terms and Conditions',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Toast />
<ConfirmDialog></ConfirmDialog>
<ConfirmDialog group="templating">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{slotProps.message.message}}</p>
</div>
</template>
</ConfirmDialog>
<ConfirmDialog group="positionDialog"></ConfirmDialog>
<div class="card">
<h5>Basic</h5>
<Button @click="confirm1()" icon="pi pi-check" label="Confirm" class="mr-2"></Button>
<Button @click="confirm2()" icon="pi pi-times" label="Delete"></Button>
<h5>Templating</h5>
<Button @click="showTemplate()" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></Button>
<h5>Position</h5>
<div class="grid flex-column">
<div class="p-col">
<Button @click="confirmPosition('left')" icon="pi pi-arrow-right" label="Left" class="p-button-help mr-2"></Button>
<Button @click="confirmPosition('right')" icon="pi pi-arrow-left" label="Right" class="p-button-help"></Button>
</div>
<div class="p-col">
<Button @click="confirmPosition('topleft')" icon="pi pi-arrow-down-right" label="TopLeft" class="p-button-warning mr-2"></Button>
<Button @click="confirmPosition('top')" icon="pi pi-arrow-down" label="Top" class="p-button-warning mr-2"></Button>
<Button @click="confirmPosition('topright')" icon="pi pi-arrow-down-left" label="TopRight" class="p-button-warning"></Button>
</div>
<div class="p-col">
<Button @click="confirmPosition('bottomleft')" icon="pi pi-arrow-up-right" label="BottomLeft" class="p-button-success mr-2"></Button>
<Button @click="confirmPosition('bottom')" icon="pi pi-arrow-up" label="Bottom" class="p-button-success mr-2"></Button>
<Button @click="confirmPosition('bottomright')" icon="pi pi-arrow-up-left" label="BottomRight" class="p-button-success"></Button>
</div>
</div>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import { useConfirm } from "primevue/useconfirm";
import { useToast } from "primevue/usetoast";
export default defineComponent({
setup() {
const confirm = useConfirm();
const toast = useToast();
const confirm1 = () => {
confirm.require({
message: 'Are you sure you want to proceed?',
header: 'Confirmation',
icon: 'pi pi-exclamation-triangle',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const confirm2 = () => {
confirm.require({
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const confirmPosition = (position) => {
confirm.require({
group: 'positionDialog',
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
position: position,
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const showTemplate = () => {
confirm.require({
group: 'templating',
header: 'Terms and Conditions',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
return { confirm1, confirm2, confirmPosition, showTemplate };
}
});
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/confirmdialog/confirmdialog.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/confirmationservice/confirmationservice.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>`,
content: `<div id="app">
<p-toast></p-toast>
<p-confirmdialog></p-confirmdialog>
<p-confirmdialog group="templating">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{slotProps.message.message}}</p>
</div>
</template>
</p-confirmdialog>
<p-confirmdialog group="positionDialog"></p-confirmdialog>
<div class="card">
<h5>Basic</h5>
<p-button @click="confirm1()" icon="pi pi-check" label="Confirm" class="mr-2"></p-button>
<p-button @click="confirm2()" icon="pi pi-times" label="Delete"></p-button>
<h5>Templating</h5>
<p-button @click="showTemplate()" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></p-button>
<h5>Position</h5>
<div class="grid flex-column">
<div class="p-col">
<p-button @click="confirmPosition('left')" icon="pi pi-arrow-right" label="Left" class="p-button-help mr-2"></p-button>
<p-button @click="confirmPosition('right')" icon="pi pi-arrow-left" label="Right" class="p-button-help"></p-button>
</div>
<div class="p-col">
<p-button @click="confirmPosition('topleft')" icon="pi pi-arrow-down-right" label="TopLeft" class="p-button-warning mr-2"></p-button>
<p-button @click="confirmPosition('top')" icon="pi pi-arrow-down" label="Top" class="p-button-warning mr-2"></p-button>
<p-button @click="confirmPosition('topright')" icon="pi pi-arrow-down-left" label="TopRight" class="p-button-warning"></p-button>
</div>
<div class="p-col">
<p-button @click="confirmPosition('bottomleft')" icon="pi pi-arrow-up-right" label="BottomLeft" class="p-button-success mr-2"></p-button>
<p-button @click="confirmPosition('bottom')" icon="pi pi-arrow-up" label="Bottom" class="p-button-success mr-2"></p-button>
<p-button @click="confirmPosition('bottomright')" icon="pi pi-arrow-up-left" label="BottomRight" class="p-button-success"></p-button>
</div>
</div>
</div>
</div>
<script type="module">
const { createApp } = Vue;
const { useConfirm } = primevue.useconfirm;
const { useToast } = primevue.usetoast;
const App = {
setup() {
const confirm = useConfirm();
const toast = useToast();
const confirm1 = () => {
confirm.require({
message: 'Are you sure you want to proceed?',
header: 'Confirmation',
icon: 'pi pi-exclamation-triangle',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const confirm2 = () => {
confirm.require({
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const confirmPosition = (position) => {
confirm.require({
group: 'positionDialog',
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
position: position,
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const showTemplate = () => {
confirm.require({
group: 'templating',
header: 'Terms and Conditions',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
return { confirm1, confirm2, confirmPosition, showTemplate };
},
components: {
"p-confirmdialog": primevue.confirmdialog,
"p-toast": primevue.toast,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.confirmationservice)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

View File

@ -0,0 +1,123 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>ConfirmDialog</h1>
<p>ConfirmDialog uses a Dialog UI that is integrated with the Confirmation API.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<ConfirmDialog></ConfirmDialog>
<ConfirmDialog group="templating">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{ slotProps.message.message }}</p>
</div>
</template>
</ConfirmDialog>
<ConfirmDialog group="positionDialog"></ConfirmDialog>
<div class="card">
<h5>Basic</h5>
<Button @click="confirm1()" icon="pi pi-check" label="Confirm" class="mr-2"></Button>
<Button @click="confirm2()" icon="pi pi-times" label="Delete"></Button>
<h5>Templating</h5>
<Button @click="showTemplate()" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></Button>
<h5>Position</h5>
<div class="grid flex-column">
<div class="col">
<Button @click="confirmPosition('left')" icon="pi pi-arrow-right" label="Left" class="p-button-help mr-2"></Button>
<Button @click="confirmPosition('right')" icon="pi pi-arrow-left" label="Right" class="p-button-help"></Button>
</div>
<div class="col">
<Button @click="confirmPosition('topleft')" icon="pi pi-arrow-down-right" label="TopLeft" class="p-button-warning mr-2"></Button>
<Button @click="confirmPosition('top')" icon="pi pi-arrow-down" label="Top" class="p-button-warning mr-2"></Button>
<Button @click="confirmPosition('topright')" icon="pi pi-arrow-down-left" label="TopRight" class="p-button-warning"></Button>
</div>
<div class="col">
<Button @click="confirmPosition('bottomleft')" icon="pi pi-arrow-up-right" label="BottomLeft" class="p-button-success mr-2"></Button>
<Button @click="confirmPosition('bottom')" icon="pi pi-arrow-up" label="Bottom" class="p-button-success mr-2"></Button>
<Button @click="confirmPosition('bottomright')" icon="pi pi-arrow-up-left" label="BottomRight" class="p-button-success"></Button>
</div>
</div>
</div>
</div>
<ConfirmDialogDoc />
</div>
</template>
<script>
import ConfirmDialogDoc from './ConfirmDialogDoc';
export default {
methods: {
confirm1() {
this.$confirm.require({
message: 'Are you sure you want to proceed?',
header: 'Confirmation',
icon: 'pi pi-exclamation-triangle',
accept: () => {
this.$toast.add({ severity: 'info', summary: 'Confirmed', detail: 'You have accepted', life: 3000 });
},
reject: () => {
this.$toast.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
},
confirm2() {
this.$confirm.require({
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
this.$toast.add({ severity: 'info', summary: 'Confirmed', detail: 'Record deleted', life: 3000 });
},
reject: () => {
this.$toast.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
},
confirmPosition(position) {
this.$confirm.require({
group: 'positionDialog',
message: 'Do you want to delete this record?',
header: 'Delete Confirmation',
icon: 'pi pi-info-circle',
position: position,
accept: () => {
this.$toast.add({ severity: 'info', summary: 'Confirmed', detail: 'Record deleted', life: 3000 });
},
reject: () => {
this.$toast.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
},
showTemplate() {
this.$confirm.require({
group: 'templating',
header: 'Terms and Conditions',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
this.$toast.add({ severity: 'info', summary: 'Confirmed', detail: 'You have accepted', life: 3000 });
},
reject: () => {
this.$toast.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
}
},
components: {
ConfirmDialogDoc: ConfirmDialogDoc
}
};
</script>

View File

@ -0,0 +1,585 @@
<template>
<AppDoc name="ConfirmPopupDemo" :sources="sources" github="confirmpopup/ConfirmPopupDemo.vue">
<h5>ConfirmationService</h5>
<p>ConfirmPopup is controlled via the <i>ConfirmationService</i> that needs to be installed globally before the application instance is created.</p>
<pre v-code.script><code>
import {createApp} from 'vue';
import ConfirmationService from 'primevue/confirmationservice';
const app = createApp(App);
app.use(ConfirmationService);
</code></pre>
<h5>Import via Module</h5>
<pre v-code.script><code>
import ConfirmPopup from 'primevue/confirmpopup';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/confirmpopup/confirmpopup.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>ConfirmPopup is displayed by calling the <i>require</i> method of the <i>$confirm</i> instance by passing the options to customize the Popup. <i>target</i> attribute is mandatory to align the popup to its caller.</p>
<pre v-code><code>
&lt;ConfirmPopup&gt;&lt;/ConfirmPopup&gt;
&lt;Button @click="delete($event)" icon="pi pi-check" label="Confirm"&gt;&lt;/Button&gt;
</code></pre>
<pre v-code.script><code>
export default {
methods: {
delete(event) {
this.$confirm.require({
target: event.currentTarget,
message: 'Are you sure you want to proceed?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
//callback to execute when user confirms the action
},
reject: () => {
//callback to execute when user rejects the action
}
});
},
}
}
</code></pre>
<h5>Composition API</h5>
<p>The service can be injected with the <i>useConfirm</i> function.</p>
<pre v-code.script><code>
import { defineComponent } from "vue";
import { useConfirm } from "primevue/useconfirm";
export default defineComponent({
setup() {
const confirm = useConfirm();
function delete(event) {
confirm.require({
message: 'Are you sure you want to proceed?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
//callback to execute when user confirms the action
},
reject: () => {
//callback to execute when user rejects the action
}
});
}
return {delete};
}
})
</code></pre>
<h5>Close Confirmation</h5>
<p>The popup can also be hidden programmatically using the <i>close</i> method.</p>
<pre v-code.script><code>
export default {
methods: {
discard() {
this.$confirm.close();
}
}
}
</code></pre>
<h5>Templating</h5>
<p>Templating allows customizing the content where the message instance is available as the implicit variable.</p>
<pre v-code><code><template v-pre>
&lt;ConfirmPopup group="demo">
&lt;template #message="slotProps"&gt;
&lt;div class="flex p-4"&gt;
&lt;i :class="slotProps.message.icon" style="font-size: 1.5rem"&gt;&lt;/i&gt;
&lt;p class="pl-2"&gt;{{slotProps.message.message}}&lt;/p&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/ConfirmPopup&gt;
</template>
</code></pre>
<h5>Confirmation Options</h5>
<p>ConfirmDialog can be customized with various options listed here.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>target</td>
<td>DomElement</td>
<td>null</td>
<td>Element to align the overlay.</td>
</tr>
<tr>
<td>message</td>
<td>string</td>
<td>null</td>
<td>Message of the confirmation.</td>
</tr>
<tr>
<td>group</td>
<td>string</td>
<td>null</td>
<td>Optional key to match the key of the confirmation, useful to target a specific confirm dialog instance.</td>
</tr>
<tr>
<td>icon</td>
<td>string</td>
<td>null</td>
<td>Icon to display next to the message.</td>
</tr>
<tr>
<td>accept</td>
<td>Function</td>
<td>null</td>
<td>Callback to execute when action is confirmed.</td>
</tr>
<tr>
<td>reject</td>
<td>Function</td>
<td>null</td>
<td>Callback to execute when action is rejected.</td>
</tr>
<tr>
<td>acceptLabel</td>
<td>string</td>
<td>null</td>
<td>Label of the accept button. Defaults to PrimeVue <router-link to="/locale">Locale</router-link> configuration.</td>
</tr>
<tr>
<td>rejectLabel</td>
<td>string</td>
<td>null</td>
<td>Label of the reject button. Defaults to PrimeVue <router-link to="/locale">Locale</router-link> configuration.</td>
</tr>
<tr>
<td>acceptIcon</td>
<td>string</td>
<td>null</td>
<td>Icon of the accept button.</td>
</tr>
<tr>
<td>rejectIcon</td>
<td>string</td>
<td>null</td>
<td>Icon of the reject button.</td>
</tr>
<tr>
<td>acceptClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the accept button.</td>
</tr>
<tr>
<td>rejectClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the reject button.</td>
</tr>
</tbody>
</table>
</div>
<h5>ConfirmationService</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>require</td>
<td>confirm: Confirmation Object</td>
<td>Displays the dialog using the confirmation object options.</td>
</tr>
<tr>
<td>close</td>
<td>-</td>
<td>Hides the dialog without invoking accept or reject callbacks.</td>
</tr>
</tbody>
</table>
</div>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>group</td>
<td>string</td>
<td>null</td>
<td>Optional key to match the key of the confirmation, useful to target a specific confirm dialog instance.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>message</td>
<td>-</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>ConfirmDialog inherits all the classes from the Dialog component, visit <router-link to="/dialog">dialog</router-link> for more information.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-confirm-popup</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-confirm-popup-content</td>
<td>Content element.</td>
</tr>
<tr>
<td>p-confirm-popup-icon</td>
<td>Message icon.</td>
</tr>
<tr>
<td>p-confirm-popup-message</td>
<td>Message text.</td>
</tr>
<tr>
<td>p-confirm-popup-footer</td>
<td>Footer element for buttons.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<ConfirmPopup></ConfirmPopup>
<ConfirmPopup group="demo">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{slotProps.message.message}}</p>
</div>
</template>
</ConfirmPopup>
<Toast />
<div class="card">
<h5>Overlay</h5>
<Button @click="confirm1($event)" icon="pi pi-check" label="Confirm" class="mr-2"></Button>
<Button @click="confirm2($event)" icon="pi pi-times" label="Delete" class="p-button-danger p-button-outlined"></Button>
<h5>Templating</h5>
<Button @click="showTemplate($event)" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></Button>
</div>
</div>
</template>
<script>
export default {
methods: {
confirm1(event) {
this.$confirm.require({
target: event.currentTarget,
message: 'Are you sure you want to proceed?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
},
confirm2(event) {
this.$confirm.require({
target: event.currentTarget,
message: 'Do you want to delete this record?',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
},
showTemplate(event) {
this.$confirm.require({
target: event.currentTarget,
group: 'demo',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
this.$toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
this.$toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `<template>
<div>
<ConfirmPopup></ConfirmPopup>
<ConfirmPopup group="demo">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{slotProps.message.message}}</p>
</div>
</template>
</ConfirmPopup>
<Toast />
<div class="card">
<h5>Overlay</h5>
<Button @click="confirm1($event)" icon="pi pi-check" label="Confirm" class="mr-2"></Button>
<Button @click="confirm2($event)" icon="pi pi-times" label="Delete" class="p-button-danger p-button-outlined"></Button>
<h5>Templating</h5>
<Button @click="showTemplate($event)" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></Button>
</div>
</div>
</template>
<script>
import { defineComponent } from "vue";
import { useConfirm } from "primevue/useconfirm";
import { useToast } from "primevue/usetoast";
export default defineComponent({
setup() {
const confirm = useConfirm();
const toast = useToast();
const confirm1 = (event) => {
confirm.require({
target: event.currentTarget,
message: 'Are you sure you want to proceed?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const confirm2 = (event) => {
confirm.require({
target: event.currentTarget,
message: 'Do you want to delete this record?',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const showTemplate = (event) => {
confirm.require({
target: event.currentTarget,
group: 'demo',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
return { confirm1, confirm2, showTemplate };
},
})
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/confirmpopup/confirmpopup.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/confirmationservice/confirmationservice.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>`,
content: `<div id="app">
<p-confirmpopup></p-confirmpopup>
<p-confirmpopup group="demo">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{slotProps.message.message}}</p>
</div>
</template>
</p-confirmpopup>
<p-toast></p-toast>
<div class="card">
<h5>Overlay</h5>
<p-button @click="confirm1($event)" icon="pi pi-check" label="Confirm" class="mr-2"></p-button>
<p-button @click="confirm2($event)" icon="pi pi-times" label="Delete" class="p-button-danger p-button-outlined"></p-button>
<h5>Templating</h5>
<p-button @click="showTemplate($event)" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></p-button>
</div>
</div>
<script type="module">
const { createApp } = Vue;
const { useConfirm } = primevue.useconfirm;
const { useToast } = primevue.usetoast;
const App = {
setup() {
const confirm = useConfirm();
const toast = useToast();
const confirm1 = (event) => {
confirm.require({
target: event.currentTarget,
message: 'Are you sure you want to proceed?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const confirm2 = (event) => {
confirm.require({
target: event.currentTarget,
message: 'Do you want to delete this record?',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'Record deleted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
const showTemplate = (event) => {
confirm.require({
target: event.currentTarget,
group: 'demo',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
toast.add({severity:'info', summary:'Confirmed', detail:'You have accepted', life: 3000});
},
reject: () => {
toast.add({severity:'error', summary:'Rejected', detail:'You have rejected', life: 3000});
}
});
}
return { confirm1, confirm2, showTemplate };
},
components: {
"p-confirmpopup": primevue.confirmpopup,
"p-toast": primevue.toast,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.confirmationservice)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

View File

@ -0,0 +1,89 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>ConfirmPopup</h1>
<p>ConfirmPopup displays a confirmation overlay displayed relatively to its target.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<ConfirmPopup></ConfirmPopup>
<ConfirmPopup group="demo">
<template #message="slotProps">
<div class="flex p-4">
<i :class="slotProps.message.icon" style="font-size: 1.5rem"></i>
<p class="pl-2">{{ slotProps.message.message }}</p>
</div>
</template>
</ConfirmPopup>
<div class="card">
<h5>Overlay</h5>
<Button @click="confirm1($event)" icon="pi pi-check" label="Confirm" class="mr-2"></Button>
<Button @click="confirm2($event)" icon="pi pi-times" label="Delete" class="p-button-danger p-button-outlined"></Button>
<h5>Templating</h5>
<Button @click="showTemplate($event)" icon="pi pi-check" label="Terms and Conditions" class="mr-2"></Button>
</div>
</div>
<ConfirmPopupDoc />
</div>
</template>
<script>
import ConfirmPopupDoc from './ConfirmPopupDoc';
export default {
methods: {
confirm1(event) {
this.$confirm.require({
target: event.currentTarget,
message: 'Are you sure you want to proceed?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
this.$toast.add({ severity: 'info', summary: 'Confirmed', detail: 'You have accepted', life: 3000 });
},
reject: () => {
this.$toast.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
},
confirm2(event) {
this.$confirm.require({
target: event.currentTarget,
message: 'Do you want to delete this record?',
icon: 'pi pi-info-circle',
acceptClass: 'p-button-danger',
accept: () => {
this.$toast.add({ severity: 'info', summary: 'Confirmed', detail: 'Record deleted', life: 3000 });
},
reject: () => {
this.$toast.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
},
showTemplate(event) {
this.$confirm.require({
target: event.currentTarget,
group: 'demo',
message: 'Do you accept that?',
icon: 'pi pi-question-circle',
acceptIcon: 'pi pi-check',
rejectIcon: 'pi pi-times',
accept: () => {
this.$toast.add({ severity: 'info', summary: 'Confirmed', detail: 'You have accepted', life: 3000 });
},
reject: () => {
this.$toast.add({ severity: 'error', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
}
},
components: {
ConfirmPopupDoc: ConfirmPopupDoc
}
};
</script>

View File

@ -0,0 +1,853 @@
<template>
<AppDoc name="ContextMenuDemo" :sources="sources" github="contextmenu/ContextMenuDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import ContextMenu from 'primevue/contextmenu';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/contextmenu/contextmenu.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>MenuModel</h5>
<p>ContextMenu uses the common MenuModel API to define the items, visit <router-link to="/menumodel">MenuModel API</router-link> for details.</p>
<h5>Getting Started</h5>
<p>ContextMenu requires a collection of menuitems as its model.</p>
<pre v-code.script><code>
export default {
data() {
return {
items: [
{
label:'File',
icon:'pi pi-fw pi-file',
items:[
{
label:'New',
icon:'pi pi-fw pi-plus',
items:[
{
label:'Bookmark',
icon:'pi pi-fw pi-bookmark'
},
{
label:'Video',
icon:'pi pi-fw pi-video'
}
]
},
{
label:'Delete',
icon:'pi pi-fw pi-trash'
},
{
separator:true
},
{
label:'Export',
icon:'pi pi-fw pi-external-link'
}
]
},
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Left',
icon:'pi pi-fw pi-align-left'
},
{
label:'Right',
icon:'pi pi-fw pi-align-right'
},
{
label:'Center',
icon:'pi pi-fw pi-align-center'
},
{
label:'Justify',
icon:'pi pi-fw pi-align-justify'
},
]
},
{
label:'Users',
icon:'pi pi-fw pi-user',
items:[
{
label:'New',
icon:'pi pi-fw pi-user-plus',
},
{
label:'Delete',
icon:'pi pi-fw pi-user-minus',
},
{
label:'Search',
icon:'pi pi-fw pi-users',
items:[
{
label:'Filter',
icon:'pi pi-fw pi-filter',
items:[
{
label:'Print',
icon:'pi pi-fw pi-print'
}
]
},
{
icon:'pi pi-fw pi-bars',
label:'List'
}
]
}
]
},
{
label:'Events',
icon:'pi pi-fw pi-calendar',
items:[
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Save',
icon:'pi pi-fw pi-calendar-plus'
},
{
label:'Delete',
icon:'pi pi-fw pi-calendar-minus'
},
]
},
{
label:'Archieve',
icon:'pi pi-fw pi-calendar-times',
items:[
{
label:'Remove',
icon:'pi pi-fw pi-calendar-minus'
}
]
}
]
},
{
separator:true
},
{
label:'Quit',
icon:'pi pi-fw pi-power-off'
}
]
}
}
}
</code></pre>
<h5>Document Menu</h5>
<p>Setting global property attaches the context menu to the document.</p>
<pre v-code><code>
&lt;ContextMenu :global="true" :model="items" /&gt;
</code></pre>
<h5>Element Menu</h5>
<p>ContextMenu is attached to a custom element manually using the reference and calling the <i>show(event)</i> method.</p>
<pre v-code><code>
&lt;img alt="logo" src="demo/images/nature/nature3.jpg" @contextmenu="onImageRightClick"&gt;
&lt;ContextMenu ref="menu" :model="items" /&gt;
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
items: //items
}
},
methods: {
onImageRightClick(event) {
this.$refs.menu.show(event);
}
}
}
</code></pre>
<h5>Templating</h5>
<p>ContextMenu offers content customization with the <i>item</i> template that receives the menuitem instance from the model as a parameter.</p>
<pre v-code><code><template v-pre>
&lt;ContextMenu :model="items"&gt;
&lt;template #item="{item}"&gt;
&lt;a :href="item.url"&gt;{{item.label}}&lt;/a&gt;
&lt;/template&gt;
&lt;/ContextMenu&gt;
</template>
</code></pre>
<p><i>router-link</i> with route configuration can also be used within templating for further customization.</p>
<pre v-code><code><template v-pre>
&lt;ContextMenu :model="items"&gt;
&lt;template #item="{item}"&gt;
&lt;router-link :to="item.to" custom v-slot="{href, route, navigate, isActive, isExactActive}"&gt;
&lt;a :href="href" @click="navigate" :class="{'active-link': isActive, 'active-link-exact": isExactActive}&gt;{{route.fullPath}}&lt;/a&gt;
&lt;/router-link&gt;
&lt;/template&gt;
&lt;/ContextMenu&gt;
</template>
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>model</td>
<td>array</td>
<td>null</td>
<td>An array of menuitems.</td>
</tr>
<tr>
<td>appendTo</td>
<td>string</td>
<td>body</td>
<td>A valid query selector or an HTMLElement to specify where the overlay gets attached.</td>
</tr>
<tr>
<td>baseZIndex</td>
<td>number</td>
<td>0</td>
<td>Base zIndex value to use in layering.</td>
</tr>
<tr>
<td>autoZIndex</td>
<td>boolean</td>
<td>true</td>
<td>Whether to automatically manage layering.</td>
</tr>
<tr>
<td>global</td>
<td>boolean</td>
<td>false</td>
<td>Attaches the menu to document instead of a particular item.</td>
</tr>
<tr>
<td>exact</td>
<td>boolean</td>
<td>true</td>
<td>Whether to apply 'router-link-active-exact' class if route exactly matches the item path.</td>
</tr>
</tbody>
</table>
</div>
<h5>Methods</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>toggle</td>
<td>event: Browser event</td>
<td>Toggles the visibility of the menu.</td>
</tr>
<tr>
<td>show</td>
<td>event: Browser event</td>
<td>Shows the menu.</td>
</tr>
<tr>
<td>hide</td>
<td>-</td>
<td>Hides the menu.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>item</td>
<td>item: Menuitem instance</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-contextmenu</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-submenu-list</td>
<td>Submenu list element.</td>
</tr>
<tr>
<td>p-menuitem</td>
<td>Menuitem element.</td>
</tr>
<tr>
<td>p-menuitem-active</td>
<td>Active menuitem element.</td>
</tr>
<tr>
<td>p-menuitem-text</td>
<td>Label of a menuitem.</td>
</tr>
<tr>
<td>p-menuitem-icon</td>
<td>Icon of a menuitem.</td>
</tr>
<tr>
<td>p-submenu-icon</td>
<td>Arrow icon of a submenu.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<img alt="logo" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" @contextmenu="onImageRightClick" aria-haspopup="true">
<ContextMenu ref="menu" :model="items" />
</div>
</template>
<script>
export default {
data() {
return {
items: [
{
label:'File',
icon:'pi pi-fw pi-file',
items:[
{
label:'New',
icon:'pi pi-fw pi-plus',
items:[
{
label:'Bookmark',
icon:'pi pi-fw pi-bookmark'
},
{
label:'Video',
icon:'pi pi-fw pi-video'
},
]
},
{
label:'Delete',
icon:'pi pi-fw pi-trash'
},
{
separator:true
},
{
label:'Export',
icon:'pi pi-fw pi-external-link'
}
]
},
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Left',
icon:'pi pi-fw pi-align-left'
},
{
label:'Right',
icon:'pi pi-fw pi-align-right'
},
{
label:'Center',
icon:'pi pi-fw pi-align-center'
},
{
label:'Justify',
icon:'pi pi-fw pi-align-justify'
},
]
},
{
label:'Users',
icon:'pi pi-fw pi-user',
items:[
{
label:'New',
icon:'pi pi-fw pi-user-plus',
},
{
label:'Delete',
icon:'pi pi-fw pi-user-minus',
},
{
label:'Search',
icon:'pi pi-fw pi-users',
items:[
{
label:'Filter',
icon:'pi pi-fw pi-filter',
items:[
{
label:'Print',
icon:'pi pi-fw pi-print'
}
]
},
{
icon:'pi pi-fw pi-bars',
label:'List'
}
]
}
]
},
{
label:'Events',
icon:'pi pi-fw pi-calendar',
items:[
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Save',
icon:'pi pi-fw pi-calendar-plus'
},
{
label:'Delete',
icon:'pi pi-fw pi-calendar-minus'
},
]
},
{
label:'Archieve',
icon:'pi pi-fw pi-calendar-times',
items:[
{
label:'Remove',
icon:'pi pi-fw pi-calendar-minus'
}
]
}
]
},
{
separator:true
},
{
label:'Quit',
icon:'pi pi-fw pi-power-off'
}
]
}
},
methods: {
onImageRightClick(event) {
this.$refs.menu.show(event);
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<img alt="logo" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" @contextmenu="onImageRightClick" aria-haspopup="true">
<ContextMenu ref="menu" :model="items" />
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const menu = ref();
const items = ref([
{
label:'File',
icon:'pi pi-fw pi-file',
items:[
{
label:'New',
icon:'pi pi-fw pi-plus',
items:[
{
label:'Bookmark',
icon:'pi pi-fw pi-bookmark'
},
{
label:'Video',
icon:'pi pi-fw pi-video'
},
]
},
{
label:'Delete',
icon:'pi pi-fw pi-trash'
},
{
separator:true
},
{
label:'Export',
icon:'pi pi-fw pi-external-link'
}
]
},
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Left',
icon:'pi pi-fw pi-align-left'
},
{
label:'Right',
icon:'pi pi-fw pi-align-right'
},
{
label:'Center',
icon:'pi pi-fw pi-align-center'
},
{
label:'Justify',
icon:'pi pi-fw pi-align-justify'
},
]
},
{
label:'Users',
icon:'pi pi-fw pi-user',
items:[
{
label:'New',
icon:'pi pi-fw pi-user-plus',
},
{
label:'Delete',
icon:'pi pi-fw pi-user-minus',
},
{
label:'Search',
icon:'pi pi-fw pi-users',
items:[
{
label:'Filter',
icon:'pi pi-fw pi-filter',
items:[
{
label:'Print',
icon:'pi pi-fw pi-print'
}
]
},
{
icon:'pi pi-fw pi-bars',
label:'List'
}
]
}
]
},
{
label:'Events',
icon:'pi pi-fw pi-calendar',
items:[
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Save',
icon:'pi pi-fw pi-calendar-plus'
},
{
label:'Delete',
icon:'pi pi-fw pi-calendar-minus'
},
]
},
{
label:'Archieve',
icon:'pi pi-fw pi-calendar-times',
items:[
{
label:'Remove',
icon:'pi pi-fw pi-calendar-minus'
}
]
}
]
},
{
separator:true
},
{
label:'Quit',
icon:'pi pi-fw pi-power-off'
}
]);
const onImageRightClick = (event) => {
menu.value.show(event);
};
return { menu, items, onImageRightClick }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/vue-router@4.0.0/dist/vue-router.global.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/contextmenu/contextmenu.min.js"><\\/script>`,
content: `<div id="app">
<img alt="logo" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" @contextmenu="onImageRightClick" aria-haspopup="true">
<p-contextmenu ref="menu" :model="items"></p-contextmenu>
</div>
<script type="module">
const { createApp, ref } = Vue;
const App = {
setup() {
const menu = ref();
const items = ref([
{
label:'File',
icon:'pi pi-fw pi-file',
items:[
{
label:'New',
icon:'pi pi-fw pi-plus',
items:[
{
label:'Bookmark',
icon:'pi pi-fw pi-bookmark'
},
{
label:'Video',
icon:'pi pi-fw pi-video'
},
]
},
{
label:'Delete',
icon:'pi pi-fw pi-trash'
},
{
separator:true
},
{
label:'Export',
icon:'pi pi-fw pi-external-link'
}
]
},
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Left',
icon:'pi pi-fw pi-align-left'
},
{
label:'Right',
icon:'pi pi-fw pi-align-right'
},
{
label:'Center',
icon:'pi pi-fw pi-align-center'
},
{
label:'Justify',
icon:'pi pi-fw pi-align-justify'
},
]
},
{
label:'Users',
icon:'pi pi-fw pi-user',
items:[
{
label:'New',
icon:'pi pi-fw pi-user-plus',
},
{
label:'Delete',
icon:'pi pi-fw pi-user-minus',
},
{
label:'Search',
icon:'pi pi-fw pi-users',
items:[
{
label:'Filter',
icon:'pi pi-fw pi-filter',
items:[
{
label:'Print',
icon:'pi pi-fw pi-print'
}
]
},
{
icon:'pi pi-fw pi-bars',
label:'List'
}
]
}
]
},
{
label:'Events',
icon:'pi pi-fw pi-calendar',
items:[
{
label:'Edit',
icon:'pi pi-fw pi-pencil',
items:[
{
label:'Save',
icon:'pi pi-fw pi-calendar-plus'
},
{
label:'Delete',
icon:'pi pi-fw pi-calendar-minus'
},
]
},
{
label:'Archieve',
icon:'pi pi-fw pi-calendar-times',
items:[
{
label:'Remove',
icon:'pi pi-fw pi-calendar-minus'
}
]
}
]
},
{
separator:true
},
{
label:'Quit',
icon:'pi pi-fw pi-power-off'
}
]);
const onImageRightClick = (event) => {
menu.value.show(event);
};
return { menu, items, onImageRightClick }
},
components: {
"p-contextmenu": primevue.contextmenu
}
};
const routes = [{ path: "/", component: App }];
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes
});
createApp(App)
.use(router)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

168
pages/contextmenu/index.vue Executable file
View File

@ -0,0 +1,168 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>ContextMenu</h1>
<p>
ContextMenu displays an overlay menu on right click of its target. Note that components like DataTable has special integration with ContextMenu. Refer to documentation of the individual documentation of the with context menu
support.
</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<img alt="logo" src="demo/images/nature/nature3.jpg" @contextmenu="onImageRightClick" aria-haspopup="true" />
<ContextMenu ref="menu" :model="items" />
</div>
</div>
<ContextMenuDoc />
</div>
</template>
<script>
import ContextMenuDoc from './ContextMenuDoc';
export default {
data() {
return {
items: [
{
label: 'File',
icon: 'pi pi-fw pi-file',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-plus',
items: [
{
label: 'Bookmark',
icon: 'pi pi-fw pi-bookmark'
},
{
label: 'Video',
icon: 'pi pi-fw pi-video'
}
]
},
{
label: 'Delete',
icon: 'pi pi-fw pi-trash'
},
{
separator: true
},
{
label: 'Export',
icon: 'pi pi-fw pi-external-link'
}
]
},
{
label: 'Edit',
icon: 'pi pi-fw pi-pencil',
items: [
{
label: 'Left',
icon: 'pi pi-fw pi-align-left'
},
{
label: 'Right',
icon: 'pi pi-fw pi-align-right'
},
{
label: 'Center',
icon: 'pi pi-fw pi-align-center'
},
{
label: 'Justify',
icon: 'pi pi-fw pi-align-justify'
}
]
},
{
label: 'Users',
icon: 'pi pi-fw pi-user',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-user-plus'
},
{
label: 'Delete',
icon: 'pi pi-fw pi-user-minus'
},
{
label: 'Search',
icon: 'pi pi-fw pi-users',
items: [
{
label: 'Filter',
icon: 'pi pi-fw pi-filter',
items: [
{
label: 'Print',
icon: 'pi pi-fw pi-print'
}
]
},
{
icon: 'pi pi-fw pi-bars',
label: 'List'
}
]
}
]
},
{
label: 'Events',
icon: 'pi pi-fw pi-calendar',
items: [
{
label: 'Edit',
icon: 'pi pi-fw pi-pencil',
items: [
{
label: 'Save',
icon: 'pi pi-fw pi-calendar-plus'
},
{
label: 'Delete',
icon: 'pi pi-fw pi-calendar-minus'
}
]
},
{
label: 'Archieve',
icon: 'pi pi-fw pi-calendar-times',
items: [
{
label: 'Remove',
icon: 'pi pi-fw pi-calendar-minus'
}
]
}
]
},
{
separator: true
},
{
label: 'Quit',
icon: 'pi pi-fw pi-power-off'
}
]
};
},
methods: {
onImageRightClick(event) {
this.$refs.menu.show(event);
}
},
components: {
ContextMenuDoc: ContextMenuDoc
}
};
</script>

View File

@ -0,0 +1,47 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Basic</span></h1>
<p>DataTable requires a collection to display along with column components for the representation of the data.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
<DataTableBasicDoc />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
import DataTableBasicDoc from './DataTableBasicDoc';
export default {
data() {
return {
products: null
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
components: {
DataTableBasicDoc
}
};
</script>

View File

@ -0,0 +1,123 @@
<template>
<AppDoc name="DataTableBasicDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableBasicDemo.vue" />
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products, productService }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<p-datatable :value="products" responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, onMounted, ref } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
const app = createApp(App);
app.use(primevue.config.default);
app.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

View File

@ -0,0 +1,418 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>ColumnGroup</span></h1>
<p>Columns can be grouped at header and footer using headerColumnGroup and footerColumnGroup components.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="sales" responsiveLayout="scroll">
<ColumnGroup type="header">
<Row>
<Column header="Product" :rowspan="3" />
<Column header="Sale Rate" :colspan="4" />
</Row>
<Row>
<Column header="Sales" :colspan="2" />
<Column header="Profits" :colspan="2" />
</Row>
<Row>
<Column header="Last Year" :sortable="true" field="lastYearSale" />
<Column header="This Year" :sortable="true" field="thisYearSale" />
<Column header="Last Year" :sortable="true" field="lastYearProfit" />
<Column header="This Year" :sortable="true" field="thisYearProfit" />
</Row>
</ColumnGroup>
<Column field="product" />
<Column field="lastYearSale">
<template #body="slotProps"> {{ slotProps.data.lastYearSale }}% </template>
</Column>
<Column field="thisYearSale">
<template #body="slotProps"> {{ slotProps.data.thisYearSale }}% </template>
</Column>
<Column field="lastYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.lastYearProfit) }}
</template>
</Column>
<Column field="thisYearProfit">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.thisYearProfit) }}
</template>
</Column>
<ColumnGroup type="footer">
<Row>
<Column footer="Totals:" :colspan="3" footerStyle="text-align:right" />
<Column :footer="lastYearTotal" />
<Column :footer="thisYearTotal" />
</Row>
</ColumnGroup>
</DataTable>
</div>
</div>
<AppDoc name="DataTableColGroupDemo" :sources="sources" github="datatable/DataTableColGroupDemo.vue" />
</div>
</template>
<script>
export default {
data() {
return {
sales: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<DataTable :value="sales" responsiveLayout="scroll">
<ColumnGroup type="header">
<Row>
<Column header="Product" :rowspan="3" />
<Column header="Sale Rate" :colspan="4" />
</Row>
<Row>
<Column header="Sales" :colspan="2" />
<Column header="Profits" :colspan="2" />
</Row>
<Row>
<Column header="Last Year" :sortable="true" field="lastYearSale"/>
<Column header="This Year" :sortable="true" field="thisYearSale"/>
<Column header="Last Year" :sortable="true" field="lastYearProfit"/>
<Column header="This Year" :sortable="true" field="thisYearProfit"/>
</Row>
</ColumnGroup>
<Column field="product" />
<Column field="lastYearSale">
<template #body="slotProps">
{{slotProps.data.lastYearSale}}%
</template>
</Column>
<Column field="thisYearSale">
<template #body="slotProps">
{{slotProps.data.thisYearSale}}%
</template>
</Column>
<Column field="lastYearProfit">
<template #body="slotProps">
{{formatCurrency(slotProps.data.lastYearProfit)}}
</template>
</Column>
<Column field="thisYearProfit">
<template #body="slotProps">
{{formatCurrency(slotProps.data.thisYearProfit)}}
</template>
</Column>
<ColumnGroup type="footer">
<Row>
<Column footer="Totals:" :colspan="3" footerStyle="text-align:right"/>
<Column :footer="lastYearTotal" />
<Column :footer="thisYearTotal" />
</Row>
</ColumnGroup>
</DataTable>
</template>
<script>
export default {
data() {
return {
sales: null
}
},
created() {
this.sales = [
{product: 'Bamboo Watch', lastYearSale: 51, thisYearSale: 40, lastYearProfit: 54406, thisYearProfit: 43342},
{product: 'Black Watch', lastYearSale: 83, thisYearSale: 9, lastYearProfit: 423132, thisYearProfit: 312122},
{product: 'Blue Band', lastYearSale: 38, thisYearSale: 5, lastYearProfit: 12321, thisYearProfit: 8500},
{product: 'Blue T-Shirt', lastYearSale: 49, thisYearSale: 22, lastYearProfit: 745232, thisYearProfit: 65323},
{product: 'Brown Purse', lastYearSale: 17, thisYearSale: 79, lastYearProfit: 643242, thisYearProfit: 500332},
{product: 'Chakra Bracelet', lastYearSale: 52, thisYearSale: 65, lastYearProfit: 421132, thisYearProfit: 150005},
{product: 'Galaxy Earrings', lastYearSale: 82, thisYearSale: 12, lastYearProfit: 131211, thisYearProfit: 100214},
{product: 'Game Controller', lastYearSale: 44, thisYearSale: 45, lastYearProfit: 66442, thisYearProfit: 53322},
{product: 'Gaming Set', lastYearSale: 90, thisYearSale: 56, lastYearProfit: 765442, thisYearProfit: 296232},
{product: 'Gold Phone Case', lastYearSale: 75, thisYearSale: 54, lastYearProfit: 21212, thisYearProfit: 12533}
];
},
methods: {
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
},
computed: {
lastYearTotal() {
let total = 0;
for(let sale of this.sales) {
total += sale.lastYearProfit;
}
return this.formatCurrency(total);
},
thisYearTotal() {
let total = 0;
for(let sale of this.sales) {
total += sale.thisYearProfit;
}
return this.formatCurrency(total);
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<DataTable :value="sales" responsiveLayout="scroll">
<ColumnGroup type="header">
<Row>
<Column header="Product" :rowspan="3" />
<Column header="Sale Rate" :colspan="4" />
</Row>
<Row>
<Column header="Sales" :colspan="2" />
<Column header="Profits" :colspan="2" />
</Row>
<Row>
<Column header="Last Year" :sortable="true" field="lastYearSale"/>
<Column header="This Year" :sortable="true" field="thisYearSale"/>
<Column header="Last Year" :sortable="true" field="lastYearProfit"/>
<Column header="This Year" :sortable="true" field="thisYearProfit"/>
</Row>
</ColumnGroup>
<Column field="product" />
<Column field="lastYearSale">
<template #body="slotProps">
{{slotProps.data.lastYearSale}}%
</template>
</Column>
<Column field="thisYearSale">
<template #body="slotProps">
{{slotProps.data.thisYearSale}}%
</template>
</Column>
<Column field="lastYearProfit">
<template #body="slotProps">
{{formatCurrency(slotProps.data.lastYearProfit)}}
</template>
</Column>
<Column field="thisYearProfit">
<template #body="slotProps">
{{formatCurrency(slotProps.data.thisYearProfit)}}
</template>
</Column>
<ColumnGroup type="footer">
<Row>
<Column footer="Totals:" :colspan="3" footerStyle="text-align:right"/>
<Column :footer="lastYearTotal" />
<Column :footer="thisYearTotal" />
</Row>
</ColumnGroup>
</DataTable>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const sales = ref([
{product: 'Bamboo Watch', lastYearSale: 51, thisYearSale: 40, lastYearProfit: 54406, thisYearProfit: 43342},
{product: 'Black Watch', lastYearSale: 83, thisYearSale: 9, lastYearProfit: 423132, thisYearProfit: 312122},
{product: 'Blue Band', lastYearSale: 38, thisYearSale: 5, lastYearProfit: 12321, thisYearProfit: 8500},
{product: 'Blue T-Shirt', lastYearSale: 49, thisYearSale: 22, lastYearProfit: 745232, thisYearProfit: 65323},
{product: 'Brown Purse', lastYearSale: 17, thisYearSale: 79, lastYearProfit: 643242, thisYearProfit: 500332},
{product: 'Chakra Bracelet', lastYearSale: 52, thisYearSale: 65, lastYearProfit: 421132, thisYearProfit: 150005},
{product: 'Galaxy Earrings', lastYearSale: 82, thisYearSale: 12, lastYearProfit: 131211, thisYearProfit: 100214},
{product: 'Game Controller', lastYearSale: 44, thisYearSale: 45, lastYearProfit: 66442, thisYearProfit: 53322},
{product: 'Gaming Set', lastYearSale: 90, thisYearSale: 56, lastYearProfit: 765442, thisYearProfit: 296232},
{product: 'Gold Phone Case', lastYearSale: 75, thisYearSale: 54, lastYearProfit: 21212, thisYearProfit: 12533}
]);
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
const lastYearTotal = computed(() => {
let total = 0;
for(let sale of sales.value) {
total += sale.lastYearProfit;
}
return formatCurrency(total);
});
const thisYearTotal = computed(() => {
let total = 0;
for(let sale of sales.value) {
total += sale.thisYearProfit;
}
return formatCurrency(total);
})
return { sales, formatCurrency, lastYearTotal, thisYearTotal }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/columngroup/columngroup.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/row/row.min.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="sales" responsive-layout="scroll">
<p-columngroup type="header">
<p-row>
<p-column header="Product" :rowspan="3"></p-column>
<p-column header="Sale Rate" :colspan="4"></p-column>
</p-row>
<p-row>
<p-column header="Sales" :colspan="2"></p-column>
<p-column header="Profits" :colspan="2"></p-column>
</p-row>
<p-row>
<p-column header="Last Year" :sortable="true" field="lastYearSale"></p-column>
<p-column header="This Year" :sortable="true" field="thisYearSale"></p-column>
<p-column header="Last Year" :sortable="true" field="lastYearProfit"></p-column>
<p-column header="This Year" :sortable="true" field="thisYearProfit"></p-column>
</p-row>
</p-columngroup>
<p-column field="product"></p-column>
<p-column field="lastYearSale">
<template #body="slotProps">
{{slotProps.data.lastYearSale}}%
</template>
</p-column>
<p-column field="thisYearSale">
<template #body="slotProps">
{{slotProps.data.thisYearSale}}%
</template>
</p-column>
<p-column field="lastYearProfit">
<template #body="slotProps">
{{formatCurrency(slotProps.data.lastYearProfit)}}
</template>
</p-column>
<p-column field="thisYearProfit">
<template #body="slotProps">
{{formatCurrency(slotProps.data.thisYearProfit)}}
</template>
</p-column>
<p-columngroup type="footer">
<p-row>
<p-column footer="Totals:" :colspan="3" footer-style="text-align:right"></p-column>
<p-column :footer="lastYearTotal"></p-column>
<p-column :footer="thisYearTotal"></p-column>
</p-row>
</p-columngroup>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, computed } = Vue;
const App = {
setup() {
const sales = ref([
{product: 'Bamboo Watch', lastYearSale: 51, thisYearSale: 40, lastYearProfit: 54406, thisYearProfit: 43342},
{product: 'Black Watch', lastYearSale: 83, thisYearSale: 9, lastYearProfit: 423132, thisYearProfit: 312122},
{product: 'Blue Band', lastYearSale: 38, thisYearSale: 5, lastYearProfit: 12321, thisYearProfit: 8500},
{product: 'Blue T-Shirt', lastYearSale: 49, thisYearSale: 22, lastYearProfit: 745232, thisYearProfit: 65323},
{product: 'Brown Purse', lastYearSale: 17, thisYearSale: 79, lastYearProfit: 643242, thisYearProfit: 500332},
{product: 'Chakra Bracelet', lastYearSale: 52, thisYearSale: 65, lastYearProfit: 421132, thisYearProfit: 150005},
{product: 'Galaxy Earrings', lastYearSale: 82, thisYearSale: 12, lastYearProfit: 131211, thisYearProfit: 100214},
{product: 'Game Controller', lastYearSale: 44, thisYearSale: 45, lastYearProfit: 66442, thisYearProfit: 53322},
{product: 'Gaming Set', lastYearSale: 90, thisYearSale: 56, lastYearProfit: 765442, thisYearProfit: 296232},
{product: 'Gold Phone Case', lastYearSale: 75, thisYearSale: 54, lastYearProfit: 21212, thisYearProfit: 12533}
]);
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
const lastYearTotal = computed(() => {
let total = 0;
for(let sale of sales.value) {
total += sale.lastYearProfit;
}
return formatCurrency(total);
});
const thisYearTotal = computed(() => {
let total = 0;
for(let sale of sales.value) {
total += sale.thisYearProfit;
}
return formatCurrency(total);
});
return { sales, formatCurrency, lastYearTotal, thisYearTotal }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-columngroup": primevue.columngroup,
"p-row": primevue.row
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
created() {
this.sales = [
{ product: 'Bamboo Watch', lastYearSale: 51, thisYearSale: 40, lastYearProfit: 54406, thisYearProfit: 43342 },
{ product: 'Black Watch', lastYearSale: 83, thisYearSale: 9, lastYearProfit: 423132, thisYearProfit: 312122 },
{ product: 'Blue Band', lastYearSale: 38, thisYearSale: 5, lastYearProfit: 12321, thisYearProfit: 8500 },
{ product: 'Blue T-Shirt', lastYearSale: 49, thisYearSale: 22, lastYearProfit: 745232, thisYearProfit: 65323 },
{ product: 'Brown Purse', lastYearSale: 17, thisYearSale: 79, lastYearProfit: 643242, thisYearProfit: 500332 },
{ product: 'Chakra Bracelet', lastYearSale: 52, thisYearSale: 65, lastYearProfit: 421132, thisYearProfit: 150005 },
{ product: 'Galaxy Earrings', lastYearSale: 82, thisYearSale: 12, lastYearProfit: 131211, thisYearProfit: 100214 },
{ product: 'Game Controller', lastYearSale: 44, thisYearSale: 45, lastYearProfit: 66442, thisYearProfit: 53322 },
{ product: 'Gaming Set', lastYearSale: 90, thisYearSale: 56, lastYearProfit: 765442, thisYearProfit: 296232 },
{ product: 'Gold Phone Case', lastYearSale: 75, thisYearSale: 54, lastYearProfit: 21212, thisYearProfit: 12533 }
];
},
methods: {
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
},
computed: {
lastYearTotal() {
let total = 0;
for (let sale of this.sales) {
total += sale.lastYearProfit;
}
return this.formatCurrency(total);
},
thisYearTotal() {
let total = 0;
for (let sale of this.sales) {
total += sale.thisYearProfit;
}
return this.formatCurrency(total);
}
}
};
</script>

View File

@ -0,0 +1,205 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Column Resize</span></h1>
<p>
Columns can be resized using drag drop by setting the resizableColumns to true. There are two resize modes; "fit" and "expand". Fit is the default one and the overall table width does not change when a column is resized. In
"expand" mode, table width also changes along with the column width.
</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Fit Mode</h5>
<DataTable :value="products" :resizableColumns="true" columnResizeMode="fit" showGridlines responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Expand Mode</h5>
<DataTable :value="products" :resizableColumns="true" columnResizeMode="expand" showGridlines responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableColResizeDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableColResizeDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Fit Mode</h5>
<DataTable :value="products" :resizableColumns="true" columnResizeMode="fit" showGridlines responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Expand Mode</h5>
<DataTable :value="products" :resizableColumns="true" columnResizeMode="expand" showGridlines responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null,
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Fit Mode</h5>
<DataTable :value="products" :resizableColumns="true" columnResizeMode="fit" showGridlines responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Expand Mode</h5>
<DataTable :value="products" :resizableColumns="true" columnResizeMode="expand" showGridlines responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products, productService }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<h5>Fit Mode</h5>
<p-datatable :value="products" :resizable-columns="true" column-resize-mode="fit" show-gridlines responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Expand Mode</h5>
<p-datatable :value="products" :resizable-columns="true" column-resize-mode="expand" show-gridlines responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products, productService }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
}
};
</script>

View File

@ -0,0 +1,215 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Column Toggle</span></h1>
<p>MultiSelect component can be used to implement column toggle functionality.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
<div style="text-align: left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle" placeholder="Select Columns" style="width: 20em" />
</div>
</template>
<Column field="code" header="Code" />
<Column v-for="(col, index) of selectedColumns" :field="col.field" :header="col.header" :key="col.field + '_' + index"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableColToggleDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableColToggleDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
selectedColumns: null,
columns: null,
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
<div style="text-align:left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle"
placeholder="Select Columns" style="width: 20em"/>
</div>
</template>
<Column field="code" header="Code" />
<Column v-for="(col, index) of selectedColumns" :field="col.field" :header="col.header" :key="col.field + '_' + index"></Column>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
selectedColumns: null,
columns: null,
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
];
this.selectedColumns = this.columns;
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
onToggle(value) {
this.selectedColumns = this.columns.filter(col => value.includes(col));
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
<div style="text-align:left">
<MultiSelect :modelValue="selectedColumns" :options="columns" optionLabel="header" @update:modelValue="onToggle"
placeholder="Select Columns" style="width: 20em"/>
</div>
</template>
<Column field="code" header="Code" />
<Column v-for="(col, index) of selectedColumns" :field="col.field" :header="col.header" :key="col.field + '_' + index"></Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const columns = ref([
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
]);
const selectedColumns = ref(columns.value);
const products = ref();
const productService = ref(new ProductService());
const onToggle = (val) => {
selectedColumns.value = columns.value.filter(col => val.includes(col));
};
return { columns, selectedColumns, products, productService, onToggle }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/multiselect/multiselect.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="products" responsive-layout="scroll">
<template #header>
<div style="text-align:left">
<p-multiselect :model-value="selectedColumns" :options="columns" option-label="header" @update:model-value="onToggle"
placeholder="Select Columns" style="width: 20em"></p-multiselect>
</div>
</template>
<p-column field="code" header="Code"></p-column>
<p-column v-for="(col, index) of selectedColumns" :field="col.field" :header="col.header" :key="col.field + '_' + index"></p-column>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const columns = ref([
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
]);
const selectedColumns = ref(columns.value);
const products = ref();
const productService = ref(new ProductService());
const onToggle = (val) => {
selectedColumns.value = columns.value.filter(col => val.includes(col));
};
return { columns, selectedColumns, products, productService, onToggle }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-multiselect": primevue.multiselect
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{ field: 'name', header: 'Name' },
{ field: 'category', header: 'Category' },
{ field: 'quantity', header: 'Quantity' }
];
this.selectedColumns = this.columns;
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
onToggle(value) {
this.selectedColumns = this.columns.filter((col) => value.includes(col));
}
}
};
</script>

View File

@ -0,0 +1,272 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>ContextMenu</span></h1>
<p>DataTable has exclusive integration with ContextMenu.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" contextMenu v-model:contextMenuSelection="selectedProduct" @row-contextmenu="onRowContextMenu" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
</div>
<ContextMenu :model="menuModel" ref="cm" />
</div>
<AppDoc name="DataTableContextMenuDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableContextMenuDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
selectedProduct: null,
menuModel: [
{ label: 'View', icon: 'pi pi-fw pi-search', command: () => this.viewProduct(this.selectedProduct) },
{ label: 'Delete', icon: 'pi pi-fw pi-times', command: () => this.deleteProduct(this.selectedProduct) }
],
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Toast />
<DataTable :value="products" contextMenu v-model:contextMenuSelection="selectedProduct" @rowContextmenu="onRowContextMenu" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
<ContextMenu :model="menuModel" ref="cm" />
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null,
selectedProduct: null,
menuModel: [
{label: 'View', icon: 'pi pi-fw pi-search', command: () => this.viewProduct(this.selectedProduct)},
{label: 'Delete', icon: 'pi pi-fw pi-times', command: () => this.deleteProduct(this.selectedProduct)}
]
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
onRowContextMenu(event) {
this.$refs.cm.show(event.originalEvent);
},
viewProduct(product) {
this.$toast.add({severity: 'info', summary: 'Product Selected', detail: product.name});
},
deleteProduct(product) {
this.products = this.products.filter((p) => p.id !== product.id);
this.$toast.add({severity: 'error', summary: 'Product Deleted', detail: product.name});
this.selectedProduct = null;
},
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Toast />
<DataTable :value="products" contextMenu v-model:contextMenuSelection="selectedProduct" @rowContextmenu="onRowContextMenu" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
<ContextMenu :model="menuModel" ref="cm" />
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useToast } from 'primevue/usetoast';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const cm = ref();
const toast = useToast();
const products = ref();
const productService = ref(new ProductService());
const selectedProduct = ref();
const menuModel = ref([
{label: 'View', icon: 'pi pi-fw pi-search', command: () => viewProduct(selectedProduct)},
{label: 'Delete', icon: 'pi pi-fw pi-times', command: () => deleteProduct(selectedProduct)}
]);
const onRowContextMenu = (event) => {
cm.value.show(event.originalEvent);
};
const viewProduct = (product) => {
toast.add({severity: 'info', summary: 'Product Selected', detail: product.name});
};
const deleteProduct = (product) => {
products.value = products.value.filter((p) => p.id !== product.value.id);
toast.add({severity: 'error', summary: 'Product Deleted', detail: product.name});
selectedProduct.value = null;
};
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { cm, products, selectedProduct, menuModel, onRowContextMenu, viewProduct, deleteProduct, formatCurrency }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/contextmenu/contextmenu.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-toast></p-toast>
<p-datatable :value="products" context-menu v-model:context-menu-selection="selectedProduct" @row-contextmenu="onRowContextMenu" responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="price" header="Price">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</p-column>
</p-datatable>
<p-contextmenu :model="menuModel" ref="cm"></p-contextmenu>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const { useToast } = primevue.usetoast;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const cm = ref();
const toast = useToast();
const products = ref();
const productService = ref(new ProductService());
const selectedProduct = ref();
const menuModel = ref([
{label: 'View', icon: 'pi pi-fw pi-search', command: () => viewProduct(selectedProduct)},
{label: 'Delete', icon: 'pi pi-fw pi-times', command: () => deleteProduct(selectedProduct)}
]);
const onRowContextMenu = (event) => {
cm.value.show(event.originalEvent);
};
const viewProduct = (product) => {
toast.add({severity: 'info', summary: 'Product Selected', detail: product.name});
};
const deleteProduct = (product) => {
products.value = products.value.filter((p) => p.id !== product.value.id);
toast.add({severity: 'error', summary: 'Product Deleted', detail: product.name});
selectedProduct.value = null;
};
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { cm, products, selectedProduct, menuModel, onRowContextMenu, viewProduct, deleteProduct, formatCurrency }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-contextmenu": primevue.contextmenu,
"p-toast":primevue.toast
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
onRowContextMenu(event) {
this.$refs.cm.show(event.originalEvent);
},
viewProduct(product) {
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: product.name });
},
deleteProduct(product) {
this.products = this.products.filter((p) => p.id !== product.id);
this.$toast.add({ severity: 'error', summary: 'Product Deleted', detail: product.name });
this.selectedProduct = null;
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
}
};
</script>

File diff suppressed because it is too large Load Diff

244
pages/datatable/DataTableDemo.vue Executable file
View File

@ -0,0 +1,244 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable</h1>
<p>DataTable displays data in tabular format.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable
:value="customers"
:paginator="true"
class="p-datatable-customers"
:rows="10"
dataKey="id"
:rowHover="true"
v-model:selection="selectedCustomers"
v-model:filters="filters"
filterDisplay="menu"
:loading="loading"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
:rowsPerPageOptions="[10, 25, 50]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"
:globalFilterFields="['name', 'country.name', 'representative.name', 'status']"
responsiveLayout="scroll"
>
<template #header>
<div class="flex flex-column md:flex-row md:justify-content-between md:align-items-center">
<h5 class="m-0">Customers</h5>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters['global'].value" placeholder="Keyword Search" />
</span>
</div>
</template>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column selectionMode="multiple" style="min-width: 3rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 14rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText type="text" v-model="filterModel.value" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column field="country.name" header="Country" sortable filterMatchMode="contains" style="min-width: 14rem">
<template #body="{ data }">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + data.country.code" width="30" />
<span class="image-text">{{ data.country.name }}</span>
</template>
<template #filter="{ filterModel }">
<InputText type="text" v-model="filterModel.value" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Agent" sortable filterField="representative" sortField="representative.name" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<img :alt="data.representative.name" :src="'demo/images/avatar/' + data.representative.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ data.representative.name }}</span>
</template>
<template #filter="{ filterModel }">
<div class="mb-3 font-bold">Agent Picker</div>
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" :src="'demo/images/avatar/' + slotProps.option.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="date" header="Date" sortable dataType="date" style="min-width: 8rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<Calendar v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" />
</template>
</Column>
<Column field="balance" header="Balance" sortable dataType="numeric" style="min-width: 8rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column field="status" header="Status" sortable :filterMenuStyle="{ width: '14rem' }" style="min-width: 10rem">
<template #body="{ data }">
<span :class="'customer-badge status-' + data.status">{{ data.status }}</span>
</template>
<template #filter="{ filterModel }">
<Dropdown v-model="filterModel.value" :options="statuses" placeholder="Any" class="p-column-filter" :showClear="true">
<template #value="slotProps">
<span :class="'customer-badge status-' + slotProps.value">{{ slotProps.value }}</span>
</template>
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{ slotProps.option }}</span>
</template>
</Dropdown>
</template>
</Column>
<Column field="activity" header="Activity" sortable :showFilterMatchModes="false" style="min-width: 10rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" />
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-3"></Slider>
<div class="flex align-items-center justify-content-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column headerStyle="min-width: 4rem; text-align: center" bodyStyle="text-align: center; overflow: visible">
<template #body>
<Button type="button" icon="pi pi-cog"></Button>
</template>
</Column>
</DataTable>
</div>
</div>
<DataTableDoc />
</div>
</template>
<script>
import CustomerService from '../../service/CustomerService';
import { FilterMatchMode, FilterOperator } from 'primevue/api';
import DataTableDoc from './DataTableDoc';
export default {
data() {
return {
customers: null,
selectedCustomers: null,
filters: {
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
name: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
'country.name': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
representative: { value: null, matchMode: FilterMatchMode.IN },
date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
balance: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
activity: { value: null, matchMode: FilterMatchMode.BETWEEN },
verified: { value: null, matchMode: FilterMatchMode.EQUALS }
},
loading: true,
representatives: [
{ name: 'Amy Elsner', image: 'amyelsner.png' },
{ name: 'Anna Fali', image: 'annafali.png' },
{ name: 'Asiya Javayant', image: 'asiyajavayant.png' },
{ name: 'Bernardo Dominic', image: 'bernardodominic.png' },
{ name: 'Elwin Sharvill', image: 'elwinsharvill.png' },
{ name: 'Ioni Bowcher', image: 'ionibowcher.png' },
{ name: 'Ivan Magalhaes', image: 'ivanmagalhaes.png' },
{ name: 'Onyama Limba', image: 'onyamalimba.png' },
{ name: 'Stephen Shaw', image: 'stephenshaw.png' },
{ name: 'XuXue Feng', image: 'xuxuefeng.png' }
],
statuses: ['unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal']
};
},
created() {
this.customerService = new CustomerService();
},
mounted() {
this.customerService.getCustomersLarge().then((data) => {
this.customers = data;
this.customers.forEach((customer) => (customer.date = new Date(customer.date)));
this.loading = false;
});
},
methods: {
formatDate(value) {
return value.toLocaleDateString('en-US', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
},
components: {
DataTableDoc: DataTableDoc
}
};
</script>
<style lang="scss" scoped>
::v-deep(.p-paginator) {
.p-paginator-current {
margin-left: auto;
}
}
::v-deep(.p-progressbar) {
height: 0.5rem;
background-color: #d8dadc;
.p-progressbar-value {
background-color: #607d8b;
}
}
::v-deep(.p-datepicker) {
min-width: 25rem;
td {
font-weight: 400;
}
}
::v-deep(.p-datatable.p-datatable-customers) {
.p-datatable-header {
padding: 1rem;
text-align: left;
font-size: 1.5rem;
}
.p-paginator {
padding: 1rem;
}
.p-datatable-thead > tr > th {
text-align: left;
}
.p-datatable-tbody > tr > td {
cursor: auto;
}
.p-dropdown-label:not(.p-placeholder) {
text-transform: uppercase;
}
}
</style>

3518
pages/datatable/DataTableDoc.vue Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Dynamic Columns</span></h1>
<p>Columns can be defined dynamically using the v-for directive.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableDynamicColumnsDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableDynamicColumnsDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
columns: null,
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
columns: null,
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
];
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const productService = ref(new ProductService());
const columns = ref([
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
]);
const products = ref();
return { columns, products }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="products" responsive-layout="scroll">
<p-column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></p-column>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const productService = ref(new ProductService());
const columns = ref([
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
]);
const products = ref();
return { columns, products }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{ field: 'code', header: 'Code' },
{ field: 'name', header: 'Name' },
{ field: 'category', header: 'Category' },
{ field: 'quantity', header: 'Quantity' }
];
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
}
};
</script>

View File

@ -0,0 +1,690 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>InCell Edit</span></h1>
<p>In cell editing provides a rapid and user friendly way to manipulate the data. The datatable provides a flexible API so that the editing behavior is implemented by the page author whether it utilizes v-model or vuex.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation p-fluid">
<div class="card">
<h5>Cell Editing</h5>
<p>Validations, dynamic columns and reverting values with the escape key.</p>
<DataTable :value="products1" editMode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width: 25%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Row Editing</h5>
<DataTable :value="products2" editMode="row" dataKey="id" v-model:editingRows="editingRows" @row-edit-save="onRowEditSave" responsiveLayout="scroll">
<Column field="code" header="Code" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
<Column field="name" header="Name" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" style="width: 20%">
<template #editor="{ data, field }">
<Dropdown v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status">
<template #option="slotProps">
<span :class="'product-badge status-' + slotProps.option.value.toLowerCase()">{{ slotProps.option.label }}</span>
</template>
</Dropdown>
</template>
<template #body="slotProps">
{{ getStatusLabel(slotProps.data.inventoryStatus) }}
</template>
</Column>
<Column field="price" header="Price" style="width: 20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column :rowEditor="true" style="width: 10%; min-width: 8rem" bodyStyle="text-align:center"></Column>
</DataTable>
</div>
<div class="card">
<h5>Cell Editing with Sorting and Filter</h5>
<DataTable :value="products3" editMode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" filterDisplay="row" v-model:filters="filters" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width: 25%" sortable filter>
<template #filter="{ filterModel, filterCallback }">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" v-tooltip.top.focus="'Hit enter key to filter'" />
</template>
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableEditDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableEditDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
import { FilterMatchMode } from 'primevue/api';
export default {
data() {
return {
editingRows: [],
columns: null,
products1: null,
products2: null,
products3: null,
statuses: [
{ label: 'In Stock', value: 'INSTOCK' },
{ label: 'Low Stock', value: 'LOWSTOCK' },
{ label: 'Out of Stock', value: 'OUTOFSTOCK' }
],
filters: {
code: { value: null, matchMode: FilterMatchMode.STARTS_WITH },
name: { value: null, matchMode: FilterMatchMode.STARTS_WITH },
quantity: { value: null, matchMode: FilterMatchMode.STARTS_WITH },
price: { value: null, matchMode: FilterMatchMode.STARTS_WITH }
},
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div class="p-fluid">
<div class="card">
<h5>Cell Editing</h5>
<p>Validations, dynamic columns and reverting values with the escape key.</p>
<DataTable :value="products1" editMode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width:25%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Row Editing</h5>
<DataTable :value="products2" editMode="row" dataKey="id" v-model:editingRows="editingRows" @row-edit-save="onRowEditSave" responsiveLayout="scroll">
<Column field="code" header="Code" style="width:20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
<Column field="name" header="Name" style="width:20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" style="width:20%">
<template #editor="{ data, field }">
<Dropdown v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status">
<template #option="slotProps">
<span :class="'product-badge status-' + slotProps.option.value.toLowerCase()">{{slotProps.option.label}}</span>
</template>
</Dropdown>
</template>
<template #body="slotProps">
{{getStatusLabel(slotProps.data.inventoryStatus)}}
</template>
</Column>
<Column field="price" header="Price" style="width:20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column :rowEditor="true" style="width:10%; min-width:8rem" bodyStyle="text-align:center"></Column>
</DataTable>
</div>
<div class="card">
<h5>Cell Editing with Sorting and Filter</h5>
<DataTable :value="products3" editMode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" filterDisplay="row" v-model:filters="filters" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width:25%" sortable filter>
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" v-tooltip.top.focus="'Hit enter key to filter'"/>
</template>
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import ProductService from './service/ProductService';
import {FilterMatchMode} from 'primevue/api';
export default {
data() {
return {
editingRows: [],
columns: null,
products1: null,
products2: null,
products3: null,
statuses: [
{label: 'In Stock', value: 'INSTOCK'},
{label: 'Low Stock', value: 'LOWSTOCK'},
{label: 'Out of Stock', value: 'OUTOFSTOCK'}
],
filters: {
'code': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'name': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'quantity': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'price': {value: null, matchMode: FilterMatchMode.STARTS_WITH}
}
}
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'quantity', header: 'Quantity'},
{field: 'price', header: 'Price'}
];
},
methods: {
onCellEditComplete(event) {
let { data, newValue, field } = event;
switch (field) {
case 'quantity':
case 'price':
if (this.isPositiveInteger(newValue))
data[field] = newValue;
else
event.preventDefault();
break;
default:
if (newValue.trim().length > 0)
data[field] = newValue;
else
event.preventDefault();
break;
}
},
isPositiveInteger(val) {
let str = String(val);
str = str.trim();
if (!str) {
return false;
}
str = str.replace(/^0+/, "") || "0";
var n = Math.floor(Number(str));
return n !== Infinity && String(n) === str && n >= 0;
},
onRowEditSave(event) {
let { newData, index } = event;
this.products2[index] = newData;
},
getStatusLabel(status) {
switch(status) {
case 'INSTOCK':
return 'In Stock';
case 'LOWSTOCK':
return 'Low Stock';
case 'OUTOFSTOCK':
return 'Out of Stock';
default:
return 'NA';
}
}
},
mounted() {
this.productService.getProductsSmall().then(data => this.products1 = data);
this.productService.getProductsSmall().then(data => this.products2 = data);
this.productService.getProductsSmall().then(data => this.products3 = data);
}
}
<\\/script>
<style lang="scss" scoped>
::v-deep(.editable-cells-table td.p-cell-editing) {
padding-top: 0;
padding-bottom: 0;
}
</style>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div class="p-fluid">
<div class="card">
<h5>Cell Editing</h5>
<p>Validations, dynamic columns and reverting values with the escape key.</p>
<DataTable :value="products1" editMode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width:25%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Row Editing</h5>
<DataTable :value="products2" editMode="row" dataKey="id" v-model:editingRows="editingRows" @row-edit-save="onRowEditSave" responsiveLayout="scroll">
<Column field="code" header="Code" style="width:20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
<Column field="name" header="Name" style="width:20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" style="width:20%">
<template #editor="{ data, field }">
<Dropdown v-model="data[field]" :options="statuses" optionLabel="label" optionValue="value" placeholder="Select a Status">
<template #option="slotProps">
<span :class="'product-badge status-' + slotProps.option.value.toLowerCase()">{{slotProps.option.label}}</span>
</template>
</Dropdown>
</template>
<template #body="slotProps">
{{getStatusLabel(slotProps.data.inventoryStatus)}}
</template>
</Column>
<Column field="price" header="Price" style="width:20%">
<template #editor="{ data, field }">
<InputText v-model="data[field]" />
</template>
</Column>
<Column :rowEditor="true" style="width:10%; min-width:8rem" bodyStyle="text-align:center"></Column>
</DataTable>
</div>
<div class="card">
<h5>Cell Editing with Sorting and Filter</h5>
<DataTable :value="products3" editMode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" filterDisplay="row" v-model:filters="filters" responsiveLayout="scroll">
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width:25%" sortable filter>
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" v-tooltip.top.focus="'Hit enter key to filter'"/>
</template>
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
import {FilterMatchMode} from 'primevue/api';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products1.value = data);
productService.value.getProductsSmall().then(data => products2.value = data);
productService.value.getProductsSmall().then(data => products3.value = data);
});
const productService = ref(new ProductService());
const editingRows = ref([]);
const columns = ref([
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'quantity', header: 'Quantity'},
{field: 'price', header: 'Price'}
]);
const products1 = ref(null);
const products2 = ref(null);
const products3 = ref(null);
const statuses = ref([
{label: 'In Stock', value: 'INSTOCK'},
{label: 'Low Stock', value: 'LOWSTOCK'},
{label: 'Out of Stock', value: 'OUTOFSTOCK'}
]);
const filters = ref({
'code': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'name': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'quantity': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'price': {value: null, matchMode: FilterMatchMode.STARTS_WITH}
});
const onCellEditComplete = (event) => {
let { data, newValue, field } = event;
switch (field) {
case 'quantity':
case 'price':
if (isPositiveInteger(newValue))
data[field] = newValue;
else
event.preventDefault();
break;
default:
if (newValue.trim().length > 0)
data[field] = newValue;
else
event.preventDefault();
break;
}
};
const isPositiveInteger = (val) => {
let str = String(val);
str = str.trim();
if (!str) {
return false;
}
str = str.replace(/^0+/, "") || "0";
var n = Math.floor(Number(str));
return n !== Infinity && String(n) === str && n >= 0;
};
const onRowEditSave = (event) => {
let { newData, index } = event;
products2.value[index] = newData;
};
const getStatusLabel = (status) => {
switch(status) {
case 'INSTOCK':
return 'In Stock';
case 'LOWSTOCK':
return 'Low Stock';
case 'OUTOFSTOCK':
return 'Out of Stock';
default:
return 'NA';
}
};
return { productService, editingRows, columns, products1, products2, products3, statuses, filters, onCellEditComplete,
isPositiveInteger, onRowEditSave, getStatusLabel }
}
}
<\\/script>
<style lang="scss" scoped>
::v-deep(.editable-cells-table td.p-cell-editing) {
padding-top: 0;
padding-bottom: 0;
}
</style>`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/dropdown/dropdown.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app" class="p-fluid card">
<div class="card">
<h5>Cell Editing</h5>
<p>Validations, dynamic columns and reverting values with the escape key.</p>
<p-datatable :value="products1" edit-mode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" responsive-layout="scroll">
<p-column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width:25%">
<template #editor="{ data, field }">
<p-inputtext v-model="data[field]" autofocus></p-inputtext>
</template>
</p-column>
</p-datatable>
</div>
<div class="card">
<h5>Row Editing</h5>
<p-datatable :value="products2" edit-mode="row" dataKey="id" v-model:editing-rows="editingRows" @row-edit-save="onRowEditSave" responsive-layout="scroll">
<p-column field="code" header="Code" style="width:20%">
<template #editor="{ data, field }">
<p-inputtext v-model="data[field]" autofocus></p-inputtext>
</template>
</p-column>
<p-column field="name" header="Name" style="width:20%">
<template #editor="{ data, field }">
<p-inputtext v-model="data[field]"></p-inputtext>
</template>
</p-column>
<p-column field="inventoryStatus" header="Status" style="width:20%">
<template #editor="{ data, field }">
<p-dropdown v-model="data[field]" :options="statuses" option-label="label" option-value="value" placeholder="Select a Status">
<template #option="slotProps">
<span :class="'product-badge status-' + slotProps.option.value.toLowerCase()">{{slotProps.option.label}}</span>
</template>
</p-dropdown>
</template>
<template #body="slotProps">
{{getStatusLabel(slotProps.data.inventoryStatus)}}
</template>
</p-column>
<p-column field="price" header="Price" style="width:20%">
<template #editor="{ data, field }">
<p-inputtext v-model="data[field]"></p-inputtext>
</template>
</p-column>
<p-column :row-editor="true" style="width:10%; min-width:8rem" bodyStyle="text-align:center"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Cell Editing with Sorting and Filter</h5>
<p-datatable :value="products3" editMode="cell" @cell-edit-complete="onCellEditComplete" class="editable-cells-table" filterDisplay="row" v-model:filters="filters" responsiveLayout="scroll">
<p-column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field" style="width:25%" sortable filter>
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" v-tooltip.top.focus="'Hit enter key to filter'"/>
</template>
<template #editor="{ data, field }">
<InputText v-model="data[field]" autofocus />
</template>
</Column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const { FilterMatchMode } = primevue.api;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products1.value = data);
productService.value.getProductsSmall().then(data => products2.value = data);
productService.value.getProductsSmall().then(data => products3.value = data);
});
const productService = ref(new ProductService());
const editingRows = ref([]);
const columns = ref([
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'quantity', header: 'Quantity'},
{field: 'price', header: 'Price'}
]);
const products1 = ref(null);
const products2 = ref(null);
const products3 = ref(null);
const statuses = ref([
{label: 'In Stock', value: 'INSTOCK'},
{label: 'Low Stock', value: 'LOWSTOCK'},
{label: 'Out of Stock', value: 'OUTOFSTOCK'}
]);
const filters = ref({
'code': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'name': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'quantity': {value: null, matchMode: FilterMatchMode.STARTS_WITH},
'price': {value: null, matchMode: FilterMatchMode.STARTS_WITH}
});
const onCellEditComplete = (event) => {
let { data, newValue, field } = event;
switch (field) {
case 'quantity':
case 'price':
if (isPositiveInteger(newValue))
data[field] = newValue;
else
event.preventDefault();
break;
default:
if (newValue.trim().length > 0)
data[field] = newValue;
else
event.preventDefault();
break;
}
};
const isPositiveInteger = (val) => {
let str = String(val);
str = str.trim();
if (!str) {
return false;
}
str = str.replace(/^0+/, "") || "0";
var n = Math.floor(Number(str));
return n !== Infinity && String(n) === str && n >= 0;
};
const onRowEditSave = (event) => {
let { newData, index } = event;
products2.value[index] = newData;
};
const getStatusLabel = (status) => {
switch(status) {
case 'INSTOCK':
return 'In Stock';
case 'LOWSTOCK':
return 'Low Stock';
case 'OUTOFSTOCK':
return 'Out of Stock';
default:
return 'NA';
}
};
return { productService, editingRows, columns, products1, products2, products3, statuses, filters, onCellEditComplete,
isPositiveInteger, onRowEditSave, getStatusLabel }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-dropdown": primevue.dropdown,
"p-inputtext": primevue.inputtext
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.editable-cells-table td.p-cell-editing {
padding-top: 0;
padding-bottom: 0;
}
</style>`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{ field: 'code', header: 'Code' },
{ field: 'name', header: 'Name' },
{ field: 'quantity', header: 'Quantity' },
{ field: 'price', header: 'Price' }
];
},
methods: {
onCellEditComplete(event) {
let { data, newValue, field } = event;
switch (field) {
case 'quantity':
case 'price':
if (this.isPositiveInteger(newValue)) data[field] = newValue;
else event.preventDefault();
break;
default:
if (newValue.trim().length > 0) data[field] = newValue;
else event.preventDefault();
break;
}
},
isPositiveInteger(val) {
let str = String(val);
str = str.trim();
if (!str) {
return false;
}
str = str.replace(/^0+/, '') || '0';
var n = Math.floor(Number(str));
return n !== Infinity && String(n) === str && n >= 0;
},
onRowEditSave(event) {
let { newData, index } = event;
this.products2[index] = newData;
},
getStatusLabel(status) {
switch (status) {
case 'INSTOCK':
return 'In Stock';
case 'LOWSTOCK':
return 'Low Stock';
case 'OUTOFSTOCK':
return 'Out of Stock';
default:
return 'NA';
}
}
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products1 = data));
this.productService.getProductsSmall().then((data) => (this.products2 = data));
this.productService.getProductsSmall().then((data) => (this.products3 = data));
}
};
</script>
<style lang="scss" scoped>
::v-deep(.editable-cells-table td.p-cell-editing) {
padding-top: 0;
padding-bottom: 0;
}
</style>

View File

@ -0,0 +1,191 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Export</span></h1>
<p>DataTable can export its data to CSV format.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" ref="dt" responsiveLayout="scroll">
<template #header>
<div style="text-align: left">
<Button icon="pi pi-external-link" label="Export" @click="exportCSV($event)" />
</div>
</template>
<Column field="code" header="Code" exportHeader="Product Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableExportDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableExportDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" ref="dt" responsiveLayout="scroll">
<template #header>
<div style="text-align: left">
<Button icon="pi pi-external-link" label="Export" @click="exportCSV($event)" />
</div>
</template>
<Column field="code" header="Code" exportHeader="Product Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
exportCSV() {
this.$refs.dt.exportCSV();
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" ref="dt" responsiveLayout="scroll">
<template #header>
<div style="text-align: left">
<Button icon="pi pi-external-link" label="Export" @click="exportCSV($event)" />
</div>
</template>
<Column field="code" header="Code" exportHeader="Product Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const dt = ref();
const products = ref();
const productService = ref(new ProductService());
const exportCSV = () => {
dt.value.exportCSV();
};
return { dt, products, exportCSV }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="products" ref="dt" responsive-layout="scroll">
<template #header>
<div style="text-align: left">
<p-button icon="pi pi-external-link" label="Export" @click="exportCSV($event)"></p-button>
</div>
</template>
<p-column field="code" header="Code" exportHeader="Product Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const dt = ref();
const products = ref();
const productService = ref(new ProductService());
const exportCSV = () => {
dt.value.exportCSV();
};
return { dt, products, exportCSV }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
exportCSV() {
this.$refs.dt.exportCSV();
}
}
};
</script>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Flex Scroll</span></h1>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card" style="height: calc(100vh - 143px)">
<DataTable :value="customers" :scrollable="true" scrollHeight="flex">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Status"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableFlexScrollDemo" :sources="sources" :service="['CustomerService']" :data="['customers-large']" github="datatable/DataTableFlexScrollDemo.vue" />
</div>
</template>
<script>
import CustomerService from '../../service/CustomerService';
export default {
data() {
return {
customers: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div class="card" style="height: calc(100vh - 143px)">
<DataTable :value="customers" :scrollable="true" scrollHeight="flex">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Status"></Column>
</DataTable>
</div>
</template>
<script>
import CustomerService from './service/CustomerService';
export default {
data() {
return {
customers: null
}
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.customerService.getCustomersLarge().then(data => this.customers = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div class="card" style="height: calc(100vh - 143px)">
<DataTable :value="customers" :scrollable="true" scrollHeight="flex">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="representative.name" header="Representative"></Column>
<Column field="status" header="Status"></Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import CustomerService from './service/CustomerService';
export default {
setup() {
onMounted(() => {
customerService.value.getCustomersLarge().then(data => customers.value = data);
})
const customers = ref(null);
const customerService = ref(new CustomerService());
return { customers }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./CustomerService.js"><\\/script>`,
content: `<div id="app">
<div class="card" style="height: calc(100vh - 143px)">
<p-datatable :value="customers" :scrollable="true" scroll-height="flex">
<p-column field="name" header="Name"></p-column>
<p-column field="country.name" header="Country"></p-column>
<p-column field="representative.name" header="Representative"></p-column>
<p-column field="status" header="Status"></p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
customerService.value.getCustomersLarge().then(data => customers.value = data);
})
const customers = ref(null);
const customerService = ref(new CustomerService());
return { customers }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.customerService.getCustomersLarge().then((data) => (this.customers = data));
}
};
</script>

View File

@ -0,0 +1,172 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>GridLines</span></h1>
<p>Enabling <b>showGridlines</b> displays borders between cells. Note: Some themes may always display gridlines by design.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" showGridlines responsiveLayout="scroll">
<template #header> Header </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<template #footer> Footer </template>
</DataTable>
</div>
</div>
<AppDoc name="DataTableGridLinesDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableGridLinesDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" showGridlines responsiveLayout="scroll">
<template #header>
Header
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<template #footer>
Footer
</template>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" showGridlines responsiveLayout="scroll">
<template #header>
Header
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<template #footer>
Footer
</template>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref(null);
const productService = ref(new ProductService());
return { products }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="products" show-gridlines responsive-layout="scroll">
<template #header>
Header
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
<template #footer>
Footer
</template>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref(null);
const productService = ref(new ProductService());
return { products }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
}
};
</script>

View File

@ -0,0 +1,553 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Lazy</span></h1>
<p>
Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking corresponding callbacks everytime paging, sorting and filtering happens. Sample belows imitates lazy
paging by using an in memory list. It is also important to assign the logical number of rows to totalRecords by doing a projection query for paginator configuration so that paginator displays the UI assuming there are actually
records of totalRecords size although in reality they aren't as in lazy mode, only the records that are displayed on the current page exist. In addition, the implementation of <b>checkbox selection</b> in lazy tables is left
entirely to the user since the DataTable does not have access to the whole dataset in order to define the checked state.
</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable
:value="customers"
:lazy="true"
:paginator="true"
:rows="10"
v-model:filters="filters"
ref="dt"
dataKey="id"
:totalRecords="totalRecords"
:loading="loading"
@page="onPage($event)"
@sort="onSort($event)"
@filter="onFilter($event)"
filterDisplay="row"
:globalFilterFields="['name', 'country.name', 'company', 'representative.name']"
responsiveLayout="scroll"
v-model:selection="selectedCustomers"
:selectAll="selectAll"
@select-all-change="onSelectAllChange"
@row-select="onRowSelect"
@row-unselect="onRowUnselect"
>
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
<template #filter="{ filterModel, filterCallback }">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column field="country.name" header="Country" filterField="country.name" filterMatchMode="contains" ref="country.name" :sortable="true">
<template #filter="{ filterModel, filterCallback }">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column field="company" header="Company" filterMatchMode="contains" ref="company" :sortable="true">
<template #filter="{ filterModel, filterCallback }">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by company" />
</template>
</Column>
<Column field="representative.name" header="Representative" filterField="representative.name" ref="representative.name" :sortable="true">
<template #filter="{ filterModel, filterCallback }">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by representative" />
</template>
</Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableLazyDemo" :sources="sources" :service="['CustomerService']" github="datatable/DataTableLazyDemo.vue" />
</div>
</template>
<script>
import CustomerService from '../../service/CustomerService';
export default {
data() {
return {
loading: false,
totalRecords: 0,
customers: null,
selectedCustomers: null,
selectAll: false,
filters: {
name: { value: '', matchMode: 'contains' },
'country.name': { value: '', matchMode: 'contains' },
company: { value: '', matchMode: 'contains' },
'representative.name': { value: '', matchMode: 'contains' }
},
lazyParams: {},
columns: [
{ field: 'name', header: 'Name' },
{ field: 'country.name', header: 'Country' },
{ field: 'company', header: 'Company' },
{ field: 'representative.name', header: 'Representative' }
],
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt" dataKey="id"
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll"
v-model:selection="selectedCustomers" :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
</template>
</Column>
<Column field="country.name" header="Country" filterField="country.name" filterMatchMode="contains" ref="country.name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by country"/>
</template>
</Column>
<Column field="company" header="Company" filterMatchMode="contains" ref="company" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by company"/>
</template>
</Column>
<Column field="representative.name" header="Representative" filterField="representative.name" ref="representative.name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by representative"/>
</template>
</Column>
</DataTable>
</div>
</template>
<script>
import CustomerService from './service/CustomerService';
export default {
data() {
return {
loading: false,
totalRecords: 0,
customers: null,
selectedCustomers: null,
selectAll: false,
filters: {
'name': {value: '', matchMode: 'contains'},
'country.name': {value: '', matchMode: 'contains'},
'company': {value: '', matchMode: 'contains'},
'representative.name': {value: '', matchMode: 'contains'},
},
lazyParams: {},
columns: [
{field: 'name', header: 'Name'},
{field: 'country.name', header: 'Country'},
{field: 'company', header: 'Company'},
{field: 'representative.name', header: 'Representative'}
]
}
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.loading = true;
this.lazyParams = {
first: 0,
rows: this.$refs.dt.rows,
sortField: null,
sortOrder: null,
filters: this.filters
};
this.loadLazyData();
},
methods: {
loadLazyData() {
this.loading = true;
setTimeout(() => {
this.customerService.getCustomers(
{lazyEvent: JSON.stringify( this.lazyParams )})
.then(data => {
this.customers = data.customers;
this.totalRecords = data.totalRecords;
this.loading = false;
}
);
}, Math.random() * 1000 + 250);
},
onPage(event) {
this.lazyParams = event;
this.loadLazyData();
},
onSort(event) {
this.lazyParams = event;
this.loadLazyData();
},
onFilter() {
this.lazyParams.filters = this.filters;
this.loadLazyData();
},
onSelectAllChange(event) {
const selectAll = event.checked;
if (selectAll) {
this.customerService.getCustomers().then(data => {
this.selectAll = true;
this.selectedCustomers = data.customers;
});
}
else {
this.selectAll = false;
this.selectedCustomers = [];
}
},
onRowSelect() {
this.selectAll = this.selectedCustomers.length === this.totalRecords
},
onRowUnselect() {
this.selectAll = false;
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt" dataKey="id"
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll"
v-model:selection="selectedCustomers" :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
<Column field="name" header="Name" filterMatchMode="startsWith" ref="name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"/>
</template>
</Column>
<Column field="country.name" header="Country" filterField="country.name" filterMatchMode="contains" ref="country.name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by country"/>
</template>
</Column>
<Column field="company" header="Company" filterMatchMode="contains" ref="company" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by company"/>
</template>
</Column>
<Column field="representative.name" header="Representative" filterField="representative.name" ref="representative.name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<InputText type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by representative"/>
</template>
</Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import CustomerService from './service/CustomerService';
export default {
setup() {
onMounted(() => {
loading.value = true;
lazyParams.value = {
first: 0,
rows: dt.value.rows,
sortField: null,
sortOrder: null,
filters: filters.value
};
loadLazyData();
})
const dt = ref();
const loading = ref(false);
const totalRecords = ref(0);
const customers = ref();
const selectedCustomers = ref();
const selectAll = ref(false);
const customerService = ref(new CustomerService());
const filters = ref({
'name': {value: '', matchMode: 'contains'},
'country.name': {value: '', matchMode: 'contains'},
'company': {value: '', matchMode: 'contains'},
'representative.name': {value: '', matchMode: 'contains'},
});
const lazyParams = ref({});
const columns = ref([
{field: 'name', header: 'Name'},
{field: 'country.name', header: 'Country'},
{field: 'company', header: 'Company'},
{field: 'representative.name', header: 'Representative'}
]);
const loadLazyData = () => {
loading.value = true;
setTimeout(() => {
customerService.value.getCustomers(
{lazyEvent: JSON.stringify( lazyParams.value )})
.then(data => {
customers.value = data.customers;
totalRecords.value = data.totalRecords;
loading.value = false;
}
);
}, Math.random() * 1000 + 250);
};
const onPage = (event) => {
lazyParams.value = event;
loadLazyData();
};
const onSort = (event) => {
lazyParams.value = event;
loadLazyData();
};
const onFilter = () => {
lazyParams.value.filters = filters.value ;
loadLazyData();
}
const onSelectAllChange = (event) => {
const selectAll = event.checked;
if (selectAll) {
customerService.value.getCustomers().then(data => {
selectAll.value = true;
selectedCustomers.value = data.customers;
});
}
else {
selectAll.value = false;
selectedCustomers.value = [];
}
}
const onRowSelect = () => {
selectAll.value = selectedCustomers.value.length === totalRecords.value;
}
const onRowUnselect = () => {
selectAll.value = false;
}
return { dt, loading, totalRecords, customers, filters, lazyParams, columns, loadLazyData, onPage, onSort, onFilter, onSelectAllChange, onRowSelect, onRowUnselect }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./CustomerService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="customers" :lazy="true" :paginator="true" :rows="10" v-model:filters="filters" ref="dt" dataKey="id"
:totalRecords="totalRecords" :loading="loading" @page="onPage($event)" @sort="onSort($event)" @filter="onFilter($event)" filterDisplay="row"
:globalFilterFields="['name','country.name', 'company', 'representative.name']" responsiveLayout="scroll"
v-model:selection="selectedCustomers" :selectAll="selectAll" @select-all-change="onSelectAllChange" @row-select="onRowSelect" @row-unselect="onRowUnselect">
<p-column selectionMode="multiple" headerStyle="width: 3em"></Column>
<p-column field="name" header="Name" filter-match-mode="startsWith" ref="name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<p-inputtext type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by name"></p-inputtext>
</template>
</p-column>
<p-column field="country.name" header="Country" filter-field="country.name" filter-match-mode="contains" ref="country.name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<p-inputtext type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by country"></p-inputtext>
</template>
</p-column>
<p-column field="company" header="Company" filter-match-mode="contains" ref="company" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<p-inputtext type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by company"></p-inputtext>
</template>
</p-column>
<p-column field="representative.name" header="Representative" filter-field="representative.name" ref="representative.name" :sortable="true">
<template #filter="{filterModel,filterCallback}">
<p-inputtext type="text" v-model="filterModel.value" @keydown.enter="filterCallback()" class="p-column-filter" placeholder="Search by representative"></p-inputtext>
</template>
</p-column>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
loading.value = true;
lazyParams.value = {
first: 0,
rows: dt.value.rows,
sortField: null,
sortOrder: null,
filters: filters.value
};
loadLazyData();
})
const dt = ref();
const loading = ref(false);
const totalRecords = ref(0);
const customers = ref();
const selectedCustomers = ref();
const selectAll = ref(false);
const customerService = ref(new CustomerService());
const filters = ref({
'name': {value: '', matchMode: 'contains'},
'country.name': {value: '', matchMode: 'contains'},
'company': {value: '', matchMode: 'contains'},
'representative.name': {value: '', matchMode: 'contains'},
});
const lazyParams = ref({});
const columns = ref([
{field: 'name', header: 'Name'},
{field: 'country.name', header: 'Country'},
{field: 'company', header: 'Company'},
{field: 'representative.name', header: 'Representative'}
]);
const loadLazyData = () => {
loading.value = true;
setTimeout(() => {
customerService.value.getCustomers(
{lazyEvent: JSON.stringify( lazyParams.value )})
.then(data => {
customers.value = data.customers;
totalRecords.value = data.totalRecords;
loading.value = false;
}
);
}, Math.random() * 1000 + 250);
};
const onPage = (event) => {
lazyParams.value = event;
loadLazyData();
};
const onSort = (event) => {
lazyParams.value = event;
loadLazyData();
};
const onFilter = () => {
lazyParams.value.filters = filters.value ;
loadLazyData();
}
const onSelectAllChange = (event) => {
const selectAll = event.checked;
if (selectAll) {
customerService.value.getCustomers().then(data => {
selectAll.value = true;
selectedCustomers.value = data.customers;
});
}
else {
selectAll.value = false;
selectedCustomers.value = [];
}
}
const onRowSelect = () => {
selectAll.value = selectedCustomers.value.length === totalRecords.value;
}
const onRowUnselect = () => {
selectAll.value = false;
}
return { dt, loading, totalRecords, customers, filters, lazyParams, columns, loadLazyData, onPage, onSort, onFilter, onSelectAllChange, onRowSelect, onRowUnselect }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-inputtext": primevue.inputtext
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.loading = true;
this.lazyParams = {
first: 0,
rows: this.$refs.dt.rows,
sortField: null,
sortOrder: null,
filters: this.filters
};
this.loadLazyData();
},
methods: {
loadLazyData() {
this.loading = true;
setTimeout(() => {
this.customerService.getCustomers({ lazyEvent: JSON.stringify(this.lazyParams) }).then((data) => {
this.customers = data.customers;
this.totalRecords = data.totalRecords;
this.loading = false;
});
}, Math.random() * 1000 + 250);
},
onPage(event) {
this.lazyParams = event;
this.loadLazyData();
},
onSort(event) {
this.lazyParams = event;
this.loadLazyData();
},
onFilter() {
this.lazyParams.filters = this.filters;
this.loadLazyData();
},
onSelectAllChange(event) {
const selectAll = event.checked;
if (selectAll) {
this.customerService.getCustomers().then((data) => {
this.selectAll = true;
this.selectedCustomers = data.customers;
});
} else {
this.selectAll = false;
this.selectedCustomers = [];
}
},
onRowSelect() {
this.selectAll = this.selectedCustomers.length === this.totalRecords;
},
onRowUnselect() {
this.selectAll = false;
}
}
};
</script>

View File

@ -0,0 +1,194 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Paginator</span></h1>
<p>Pagination is enabled by setting paginator property to true and defining the rows attribute as the number of rows per page.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable
:value="customers"
:paginator="true"
:rows="10"
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
:rowsPerPageOptions="[10, 20, 50]"
responsiveLayout="scroll"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords}"
>
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="company" header="Company"></Column>
<Column field="representative.name" header="Representative"></Column>
<template #paginatorstart>
<Button type="button" icon="pi pi-refresh" class="p-button-text" />
</template>
<template #paginatorend>
<Button type="button" icon="pi pi-cloud" class="p-button-text" />
</template>
</DataTable>
</div>
</div>
<AppDoc name="DataTablePaginatorDemo" :sources="sources" :service="['CustomerService']" :data="['customers-large']" github="datatable/DataTablePaginatorDemo.vue" />
</div>
</template>
<script>
import CustomerService from '../../service/CustomerService';
export default {
data() {
return {
customers: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="customers" :paginator="true" :rows="10"
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
:rowsPerPageOptions="[10,20,50]" responsiveLayout="scroll"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords}">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="company" header="Company"></Column>
<Column field="representative.name" header="Representative"></Column>
<template #paginatorstart>
<Button type="button" icon="pi pi-refresh" class="p-button-text" />
</template>
<template #paginatorend>
<Button type="button" icon="pi pi-cloud" class="p-button-text" />
</template>
</DataTable>
</div>
</template>
<script>
import CustomerService from './service/CustomerService';
export default {
data() {
return {
customers: null
}
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.customerService.getCustomersLarge().then(data => this.customers = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="customers" :paginator="true" :rows="10"
paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
:rowsPerPageOptions="[10,20,50]" responsiveLayout="scroll"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords}">
<Column field="name" header="Name"></Column>
<Column field="country.name" header="Country"></Column>
<Column field="company" header="Company"></Column>
<Column field="representative.name" header="Representative"></Column>
<template #paginatorstart>
<Button type="button" icon="pi pi-refresh" class="p-button-text" />
</template>
<template #paginatorend>
<Button type="button" icon="pi pi-cloud" class="p-button-text" />
</template>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import CustomerService from './service/CustomerService';
export default {
setup() {
onMounted(() => {
customerService.value.getCustomersLarge().then(data => customers.value = data);
})
const customers = ref();
const customerService = ref(new CustomerService());
return { customers }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./CustomerService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="customers" :paginator="true" :rows="10"
paginator-template="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
:rows-per-page-options="[10,20,50]" responsive-layout="scroll"
current-page-report-template="Showing {first} to {last} of {totalRecords}">
<p-column field="name" header="Name"></p-column>
<p-column field="country.name" header="Country"></p-column>
<p-column field="company" header="Company"></p-column>
<p-column field="representative.name" header="Representative"></p-column>
<template #paginatorstart>
<p-button type="button" icon="pi pi-refresh" class="p-button-text"></p-button>
</template>
<template #paginatorend>
<p-button type="button" icon="pi pi-cloud" class="p-button-text"></p-button>
</template>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
customerService.value.getCustomersLarge().then(data => customers.value = data);
})
const customers = ref();
const customerService = ref(new CustomerService());
return { customers }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.customerService.getCustomersLarge().then((data) => (this.customers = data));
}
};
</script>

View File

@ -0,0 +1,218 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Reorder</span></h1>
<p>Order of the columns and rows can be changed using drag and drop.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" :reorderableColumns="true" @column-reorder="onColReorder" @row-reorder="onRowReorder" responsiveLayout="scroll">
<Column :rowReorder="true" headerStyle="width: 3rem" :reorderableColumn="false" />
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableReorderDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableReorderDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
columns: null,
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Toast />
<DataTable :value="products" :reorderableColumns="true" @columnReorder="onColReorder" @rowReorder="onRowReorder" responsiveLayout="scroll">
<Column :rowReorder="true" headerStyle="width: 3rem" :reorderableColumn="false" />
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
columns: null,
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
];
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
onColReorder() {
this.$toast.add({severity:'success', summary: 'Column Reordered', life: 3000});
},
onRowReorder(event) {
this.products = event.value;
this.$toast.add({severity:'success', summary: 'Rows Reordered', life: 3000});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Toast />
<DataTable :value="products" :reorderableColumns="true" @columnReorder="onColReorder" @rowReorder="onRowReorder" responsiveLayout="scroll">
<Column :rowReorder="true" headerStyle="width: 3rem" :reorderableColumn="false" />
<Column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useToast } from 'primevue/usetoast';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const toast = useToast();
const columns = ref([
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
]);
const products = ref();
const productService = ref(new ProductService());
const onColReorder = () => {
toast.add({severity:'success', summary: 'Column Reordered', life: 3000});
};
const onRowReorder = (event) => {
products.value = event.value;
toast.add({severity:'success', summary: 'Rows Reordered', life: 3000});
};
return { columns, products, onColReorder, onRowReorder }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-toast></p-toast>
<p-datatable :value="products" :reorderable-columns="true" @column-reorder="onColReorder" @row-reorder="onRowReorder" responsive-layout="scroll">
<p-column :row-reorder="true" header-style="width: 3rem" :reorderable-column="false"></p-column>
<p-column v-for="col of columns" :field="col.field" :header="col.header" :key="col.field"></p-column>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const { useToast } = primevue.usetoast;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const toast = useToast();
const columns = ref([
{field: 'code', header: 'Code'},
{field: 'name', header: 'Name'},
{field: 'category', header: 'Category'},
{field: 'quantity', header: 'Quantity'}
]);
const products = ref();
const productService = ref(new ProductService());
const onColReorder = () => {
toast.add({severity:'success', summary: 'Column Reordered', life: 3000});
};
const onRowReorder = (event) => {
products.value = event.value;
toast.add({severity:'success', summary: 'Rows Reordered', life: 3000});
};
return { columns, products, onColReorder, onRowReorder }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-toast": primevue.toast
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
this.columns = [
{ field: 'code', header: 'Code' },
{ field: 'name', header: 'Name' },
{ field: 'category', header: 'Category' },
{ field: 'quantity', header: 'Quantity' }
];
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
onColReorder() {
this.$toast.add({ severity: 'success', summary: 'Column Reordered', life: 3000 });
},
onRowReorder(event) {
this.products = event.value;
this.$toast.add({ severity: 'success', summary: 'Rows Reordered', life: 3000 });
}
}
};
</script>

View File

@ -0,0 +1,296 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Responsive</span></h1>
<p>DataTable responsive layout can be achieved in two ways; first approach is displaying a horizontal scrollbar for smaller screens and second one is defining a breakpoint to display the cells of a row as stacked.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header> Scroll </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{ slotProps.data.inventoryStatus }}</span>
</template>
</Column>
<Column field="rating" header="Rating">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" responsiveLayout="stack" breakpoint="960px">
<template #header> Stack </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{ slotProps.data.inventoryStatus }}</span>
</template>
</Column>
<Column field="rating" header="Rating">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableResponsiveDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableResponsiveDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
Scroll
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<Column field="rating" header="Rating">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" responsiveLayout="stack" breakpoint="960px">
<template #header>
Stack
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<Column field="rating" header="Rating">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
Scroll
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<Column field="rating" header="Rating">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" responsiveLayout="stack" breakpoint="960px">
<template #header>
Stack
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<Column field="rating" header="Rating">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/rating/rating.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<p-datatable :value="products" responsive-layout="scroll">
<template #header>
Scroll
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
<p-column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{slotProps.data.inventoryStatus}}</span>
</template>
</p-column>
<p-column field="rating" header="Rating">
<template #body="slotProps">
<p-rating :model-value="slotProps.data.rating" :readonly="true" :cancel="false"></p-rating>
</template>
</p-column>
</p-datatable>
</div>
<div class="card">
<p-datatable :value="products" responsive-layout="stack" breakpoint="960px">
<template #header>
Stack
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
<p-column field="inventoryStatus" header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{slotProps.data.inventoryStatus}}</span>
</template>
</p-column>
<p-column field="rating" header="Rating">
<template #body="slotProps">
<p-rating :model-value="slotProps.data.rating" :readonly="true" :cancel="false"></p-rating>
</template>
</p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-rating": primevue.rating
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
}
};
</script>

View File

@ -0,0 +1,494 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Row Expansion</span></h1>
<p>A row can be expanded to display additional content.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" v-model:expandedRows="expandedRows" dataKey="id" @row-expand="onRowExpand" @row-collapse="onRowCollapse" responsiveLayout="scroll">
<template #header>
<div class="table-header-container">
<Button icon="pi pi-plus" label="Expand All" @click="expandAll" class="mr-2" />
<Button icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
<Column :expander="true" headerStyle="width: 3rem" />
<Column field="name" header="Name" sortable></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.image" class="product-image" />
</template>
</Column>
<Column field="price" header="Price" sortable>
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable></Column>
<Column field="rating" header="Reviews" sortable>
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" sortable>
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{ slotProps.data.inventoryStatus }}</span>
</template>
</Column>
<template #expansion="slotProps">
<div class="orders-subtable">
<h5>Orders for {{ slotProps.data.name }}</h5>
<DataTable :value="slotProps.data.orders" responsiveLayout="scroll">
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" sortable>
<template #body="slotProps" sortable>
{{ formatCurrency(slotProps.data.amount) }}
</template>
</Column>
<Column field="status" header="Status" sortable>
<template #body="slotProps">
<span :class="'order-badge order-' + slotProps.data.status.toLowerCase()">{{ slotProps.data.status }}</span>
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</DataTable>
</div>
</div>
<AppDoc name="DataTableRowExpandDemo" :sources="sources" :service="['ProductService']" :data="['products-orders-small']" github="datatable/DataTableRowExpandDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
expandedRows: [],
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Toast />
<DataTable :value="products" v-model:expandedRows="expandedRows" dataKey="id"
@rowExpand="onRowExpand" @rowCollapse="onRowCollapse" responsiveLayout="scroll">
<template #header>
<div class="table-header-container">
<Button icon="pi pi-plus" label="Expand All" @click="expandAll" class="mr-2" />
<Button icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
<Column :expander="true" headerStyle="width: 3rem" />
<Column field="name" header="Name" sortable></Column>
<Column header="Image">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.image" class="product-image" />
</template>
</Column>
<Column field="price" header="Price" sortable>
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
<Column field="category" header="Category" sortable></Column>
<Column field="rating" header="Reviews" sortable>
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" sortable>
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<template #expansion="slotProps">
<div class="orders-subtable">
<h5>Orders for {{slotProps.data.name}}</h5>
<DataTable :value="slotProps.data.orders" responsiveLayout="scroll">
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" sortable>
<template #body="slotProps" sortable>
{{formatCurrency(slotProps.data.amount)}}
</template>
</Column>
<Column field="status" header="Status" sortable>
<template #body="slotProps">
<span :class="'order-badge order-' + slotProps.data.status.toLowerCase()">{{slotProps.data.status}}</span>
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null,
expandedRows: []
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsWithOrdersSmall().then(data => this.products = data);
},
methods: {
onRowExpand(event) {
this.$toast.add({severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000});
},
onRowCollapse(event) {
this.$toast.add({severity: 'success', summary: 'Product Collapsed', detail: event.data.name, life: 3000});
},
expandAll() {
this.expandedRows = this.products.filter(p => p.id);
this.$toast.add({severity: 'success', summary: 'All Rows Expanded', life: 3000});
},
collapseAll() {
this.expandedRows = null;
this.$toast.add({severity: 'success', summary: 'All Rows Collapsed', life: 3000});
},
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
}
}
<\\/script>
<style lang="scss" scoped>
.product-image {
width: 50px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
.orders-subtable {
padding: 1rem;
}
</style>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Toast />
<DataTable :value="products" v-model:expandedRows="expandedRows" dataKey="id"
@rowExpand="onRowExpand" @rowCollapse="onRowCollapse" responsiveLayout="scroll">
<template #header>
<div class="table-header-container">
<Button icon="pi pi-plus" label="Expand All" @click="expandAll" class="mr-2" />
<Button icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
<Column :expander="true" headerStyle="width: 3rem" />
<Column field="name" header="Name" sortable></Column>
<Column header="Image">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.image" class="product-image" />
</template>
</Column>
<Column field="price" header="Price" sortable>
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
<Column field="category" header="Category" sortable></Column>
<Column field="rating" header="Reviews" sortable>
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" sortable>
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<template #expansion="slotProps">
<div class="orders-subtable">
<h5>Orders for {{slotProps.data.name}}</h5>
<DataTable :value="slotProps.data.orders" responsiveLayout="scroll">
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" sortable>
<template #body="slotProps" sortable>
{{formatCurrency(slotProps.data.amount)}}
</template>
</Column>
<Column field="status" header="Status" sortable>
<template #body="slotProps">
<span :class="'order-badge order-' + slotProps.data.status.toLowerCase()">{{slotProps.data.status}}</span>
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useToast } from 'primevue/usetoast';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsWithOrdersSmall().then(data => products.value = data);
})
const toast = useToast();
const products = ref();
const productService = ref(new ProductService());
const expandedRows = ref([]);
const onRowExpand = (event) => {
toast.add({severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000});
};
const onRowCollapse = (event) => {
toast.add({severity: 'success', summary: 'Product Collapsed', detail: event.data.name, life: 3000});
};
const expandAll = () => {
expandedRows.value = products.value.filter(p => p.id);
toast.add({severity: 'success', summary: 'All Rows Expanded', life: 3000});
};
const collapseAll = () => {
expandedRows.value = null;
toast.add({severity: 'success', summary: 'All Rows Collapsed', life: 3000});
};
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { products, expandedRows, onRowExpand, onRowCollapse, expandAll, collapseAll, formatCurrency }
}
}
<\\/script>
<style lang="scss" scoped>
.product-image {
width: 50px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
.orders-subtable {
padding: 1rem;
}
</style>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/rating/rating.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-toast></p-toast>
<p-datatable :value="products" v-model:expanded-rows="expandedRows" dataKey="id"
@row-expand="onRowExpand" @row-collapse="onRowCollapse" responsive-layout="scroll">
<template #header>
<div class="table-header-container">
<p-button icon="pi pi-plus" label="Expand All" @click="expandAll" class="mr-2"></p-button>
<p-button icon="pi pi-minus" label="Collapse All" @click="collapseAll"></p-button>
</div>
</template>
<p-column :expander="true" headerStyle="width: 3rem"></p-column>
<p-column field="name" header="Name" sortable></p-column>
<p-column header="Image">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.image" class="product-image" />
</template>
</p-column>
<p-column field="price" header="Price" sortable>
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</p-column>
<p-column field="category" header="Category" sortable></p-column>
<p-column field="rating" header="Reviews" sortable>
<template #body="slotProps">
<p-rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false"></p-rating>
</template>
</p-column>
<p-column field="inventoryStatus" header="Status" sortable>
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
</template>
</p-column>
<template #expansion="slotProps">
<div class="orders-subtable">
<h5>Orders for {{slotProps.data.name}}</h5>
<p-datatable :value="slotProps.data.orders" responsive-layout="scroll">
<p-column field="id" header="Id" sortable></p-column>
<p-column field="customer" header="Customer" sortable></p-column>
<p-column field="date" header="Date" sortable></p-column>
<p-column field="amount" header="Amount" sortable>
<template #body="slotProps" sortable>
{{formatCurrency(slotProps.data.amount)}}
</template>
</p-column>
<p-column field="status" header="Status" sortable>
<template #body="slotProps">
<span :class="'order-badge order-' + slotProps.data.status.toLowerCase()">{{slotProps.data.status}}</span>
</template>
</p-column>
<p-column header-style="width:4rem">
<template #body>
<p-button icon="pi pi-search"></p-button>
</template>
</p-column>
</p-datatable>
</div>
</template>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const { useToast } = primevue.usetoast;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsWithOrdersSmall().then(data => products.value = data);
})
const toast = useToast();
const products = ref();
const productService = ref(new ProductService());
const expandedRows = ref([]);
const onRowExpand = (event) => {
toast.add({severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000});
};
const onRowCollapse = (event) => {
toast.add({severity: 'success', summary: 'Product Collapsed', detail: event.data.name, life: 3000});
};
const expandAll = () => {
expandedRows.value = products.value.filter(p => p.id);
toast.add({severity: 'success', summary: 'All Rows Expanded', life: 3000});
};
const collapseAll = () => {
expandedRows.value = null;
toast.add({severity: 'success', summary: 'All Rows Collapsed', life: 3000});
};
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { products, expandedRows, onRowExpand, onRowCollapse, expandAll, collapseAll, formatCurrency }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-button": primevue.button,
"p-toast": primevue.toast,
"p-rating": primevue.rating
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
<style>
.product-image {
width: 50px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
.orders-subtable {
padding: 1rem;
}
</style>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsWithOrdersSmall().then((data) => (this.products = data));
},
methods: {
onRowExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Product Expanded', detail: event.data.name, life: 3000 });
},
onRowCollapse(event) {
this.$toast.add({ severity: 'success', summary: 'Product Collapsed', detail: event.data.name, life: 3000 });
},
expandAll() {
this.expandedRows = this.products.filter((p) => p.id);
this.$toast.add({ severity: 'success', summary: 'All Rows Expanded', life: 3000 });
},
collapseAll() {
this.expandedRows = null;
this.$toast.add({ severity: 'success', summary: 'All Rows Collapsed', life: 3000 });
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
}
};
</script>
<style lang="scss" scoped>
.product-image {
width: 100px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
.orders-subtable {
padding: 1rem;
}
</style>

View File

@ -0,0 +1,683 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Row Group</span></h1>
<p>Rows can either be grouped by a separate grouping row or using rowspan.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Subheader Grouping</h5>
<p>Group customers by their representative.</p>
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 200px">
<template #body="slotProps">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{ slotProps.data.country.name }}</span>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{ slotProps.data.status }}</span>
</template>
</Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.data.representative.name }}</span>
</template>
<template #groupfooter="slotProps">
<td style="min-width: 80%">
<div style="text-align: right; width: 100%">Total Customers</div>
</td>
<td style="width: 20%">{{ calculateCustomerTotal(slotProps.data.representative.name) }}</td>
</template>
</DataTable>
</div>
<div class="card">
<h5>Expandable Row Groups</h5>
<p>Group customers by their representative.</p>
<DataTable
:value="customers"
rowGroupMode="subheader"
groupRowsBy="representative.name"
sortMode="single"
sortField="representative.name"
:sortOrder="1"
responsiveLayout="scroll"
:expandableRowGroups="true"
v-model:expandedRowGroups="expandedRowGroups"
@rowgroup-expand="onRowGroupExpand"
@rowgroup-collapse="onRowGroupCollapse"
>
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name"></Column>
<Column field="country" header="Country">
<template #body="slotProps">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{ slotProps.data.country.name }}</span>
</template>
</Column>
<Column field="company" header="Company"></Column>
<Column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{ slotProps.data.status }}</span>
</template>
</Column>
<Column field="date" header="Date"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.data.representative.name }}</span>
</template>
<template #groupfooter="slotProps">
<td colspan="4" style="text-align: right">Total Customers</td>
<td>{{ calculateCustomerTotal(slotProps.data.representative.name) }}</td>
</template>
</DataTable>
</div>
<div class="card">
<h5>RowSpan Grouping</h5>
<DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" responsiveLayout="scroll">
<Column header="#" headerStyle="width:3em">
<template #body="slotProps">
{{ slotProps.index }}
</template>
</Column>
<Column field="representative.name" header="Representative">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.data.representative.name }}</span>
</template>
</Column>
<Column field="name" header="Name"></Column>
<Column field="country" header="Country">
<template #body="slotProps">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{ slotProps.data.country.name }}</span>
</template>
</Column>
<Column field="company" header="Company"></Column>
<Column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{ slotProps.data.status }}</span>
</template>
</Column>
<Column field="date" header="Date"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableRowGroupDemo" :sources="sources" :service="['CustomerService']" :data="['customers-medium']" github="datatable/DataTableRowGroupDemo.vue" />
</div>
</template>
<script>
import CustomerService from '../../service/CustomerService';
export default {
data() {
return {
customers: null,
expandedRowGroups: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Toast />
<div class="card">
<h5>Subheader Grouping</h5>
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country" header="Country" style="min-width:200px">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date" style="min-width:200px"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td style="min-width: 80%">
<div style="text-align: right; width: 100%">Total Customers</div>
</td>
<td style="width: 20%">{{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</DataTable>
</div>
<div class="card">
<h5>Expandable Row Groups</h5>
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" responsiveLayout="scroll"
:expandableRowGroups="true" v-model:expandedRowGroups="expandedRowGroups"
@rowgroupExpand="onRowGroupExpand" @rowgroupCollapse="onRowGroupCollapse">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name"></Column>
<Column field="country" header="Country">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company"></Column>
<Column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td colspan="4" style="text-align: right">Total Customers</td>
<td>{{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</DataTable>
</div>
<div class="card">
<h5>RowSpan Grouping</h5>
<DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" responsiveLayout="scroll">
<Column header="#" headerStyle="width:3em">
<template #body="slotProps">
{{slotProps.index}}
</template>
</Column>
<Column field="representative.name" header="Representative">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
</Column>
<Column field="name" header="Name"></Column>
<Column field="country" header="Country">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company"></Column>
<Column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import CustomerService from './service/CustomerService';
export default {
data() {
return {
customers: null,
expandedRowGroups: null
}
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.customerService.getCustomersMedium().then(data => this.customers = data);
},
methods: {
onRowGroupExpand(event) {
this.$toast.add({severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000});
},
onRowGroupCollapse(event) {
this.$toast.add({severity: 'success', summary: 'Row Group Collapsed', detail: 'Value: ' + event.data, life: 3000});
},
calculateCustomerTotal(name) {
let total = 0;
if (this.customers) {
for (let customer of this.customers) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
}
}
}
<\\/script>
<style lang="scss" scoped>
.p-rowgroup-footer td {
font-weight: 700;
}
::v-deep(.p-rowgroup-header) {
span {
font-weight: 700;
}
.p-row-toggler {
vertical-align: middle;
margin-right: .25rem;
}
}
</style>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Toast />
<div class="card">
<h5>Subheader Grouping</h5>
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country" header="Country" style="min-width:200px">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date" style="min-width:200px"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td style="min-width: 80%">
<div style="text-align: right; width: 100%">Total Customers</div>
</td>
<td style="width: 20%">{{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</DataTable>
</div>
<div class="card">
<h5>Expandable Row Groups</h5>
<DataTable :value="customers" rowGroupMode="subheader" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" responsiveLayout="scroll"
:expandableRowGroups="true" v-model:expandedRowGroups="expandedRowGroups"
@rowgroupExpand="onRowGroupExpand" @rowgroupCollapse="onRowGroupCollapse">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name"></Column>
<Column field="country" header="Country">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company"></Column>
<Column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td colspan="4" style="text-align: right">Total Customers</td>
<td>{{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</DataTable>
</div>
<div class="card">
<h5>RowSpan Grouping</h5>
<DataTable :value="customers" rowGroupMode="rowspan" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" responsiveLayout="scroll">
<Column header="#" headerStyle="width:3em">
<template #body="slotProps">
{{slotProps.index}}
</template>
</Column>
<Column field="representative.name" header="Representative">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
</Column>
<Column field="name" header="Name"></Column>
<Column field="country" header="Country">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company"></Column>
<Column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useToast } from 'primevue/usetoast';
import CustomerService from './service/CustomerService';
export default {
setup() {
onMounted(() => {
customerService.value.getCustomersMedium().then(data => customers.value = data);
})
const toast = useToast();
const customers = ref();
const customerService = ref(new CustomerService());
const expandedRowGroups = ref();
const onRowGroupExpand = (event) => {
toast.add({severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000});
};
const onRowGroupCollapse = (event) => {
toast.add({severity: 'success', summary: 'Row Group Collapsed', detail: 'Value: ' + event.data, life: 3000});
};
const calculateCustomerTotal = (name) => {
let total = 0;
if (customers.value) {
for (let customer of customers.value) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
};
return { customers, expandedRowGroups, onRowGroupExpand, onRowGroupCollapse, calculateCustomerTotal }
}
}
<\\/script>
<style lang="scss" scoped>
.p-rowgroup-footer td {
font-weight: 700;
}
::v-deep(.p-rowgroup-header) {
span {
font-weight: 700;
}
.p-row-toggler {
vertical-align: middle;
margin-right: .25rem;
}
}
</style>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>
<script src="./CustomerService.js"><\\/script>`,
content: `<div id="app">
<p-toast></p-toast>
<div class="card">
<h5>Subheader Grouping</h5>
<p-datatable :value="customers" row-group-mode="subheader" group-rows-by="representative.name"
sort-mode="single" sort-field="representative.name" :sort-order="1" scrollable scroll-height="400px">
<p-column field="representative.name" header="Representative"></p-column>
<p-column field="name" header="Name" style="min-width:200px"></p-column>
<p-column field="country" header="Country" style="min-width:200px">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</p-column>
<p-column field="company" header="Company" style="min-width:200px"></p-column>
<p-column field="status" header="Status" style="min-width:200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</p-column>
<p-column field="date" header="Date" style="min-width:200px"></p-column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td style="min-width: 80%">
<div style="text-align: right; width: 100%">Total Customers</div>
</td>
<td style="width: 20%">{{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</p-datatable>
</div>
<div class="card">
<h5>Expandable Row Groups</h5>
<p-datatable :value="customers" row-group-mode="subheader" group-rows-by="representative.name"
sort-mode="single" sort-field="representative.name" :sort-order="1" responsive-layout="scroll"
:expandable-row-groups="true" v-model:expanded-row-groups="expandedRowGroups"
@rowgroup-expand="onRowGroupExpand" @rowgroup-collapse="onRowGroupCollapse">
<p-column field="representative.name" header="Representative"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="country" header="Country">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</p-column>
<p-column field="company" header="Company"></p-column>
<p-column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</p-column>
<p-column field="date" header="Date"></p-column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td colspan="4" style="text-align: right">Total Customers</td>
<td>{{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</p-datatable>
</div>
<div class="card">
<h5>RowSpan Grouping</h5>
<p-datatable :value="customers" row-group-mode="rowspan" group-rows-by="representative.name"
sort-mode="single" sort-field="representative.name" :sort-order="1" responsive-layout="scroll">
<p-column header="#" headerStyle="width:3em">
<template #body="slotProps">
{{slotProps.index}}
</template>
</p-column>
<p-column field="representative.name" header="Representative">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
</p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="country" header="Country">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</p-column>
<p-column field="company" header="Company"></p-column>
<p-column field="status" header="Status">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</p-column>
<p-column field="date" header="Date"></p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const { useToast } = primevue.usetoast;
const App = {
setup() {
onMounted(() => {
customerService.value.getCustomersMedium().then(data => customers.value = data);
})
const toast = useToast();
const customers = ref();
const customerService = ref(new CustomerService());
const expandedRowGroups = ref();
const onRowGroupExpand = (event) => {
toast.add({severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000});
};
const onRowGroupCollapse = (event) => {
toast.add({severity: 'success', summary: 'Row Group Collapsed', detail: 'Value: ' + event.data, life: 3000});
};
const calculateCustomerTotal = (name) => {
let total = 0;
if (customers.value) {
for (let customer of customers.value) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
};
return { customers, expandedRowGroups, onRowGroupExpand, onRowGroupCollapse, calculateCustomerTotal }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-toast": primevue.toast
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
<style>
.p-rowgroup-footer td {
font-weight: 700;
}
.p-rowgroup-header span {
font-weight: 700;
}
.p-rowgroup-header .p-row-toggler {
vertical-align: middle;
margin-right: .25rem;
}
</style>
`
}
}
};
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.customerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: {
onRowGroupExpand(event) {
this.$toast.add({ severity: 'info', summary: 'Row Group Expanded', detail: 'Value: ' + event.data, life: 3000 });
},
onRowGroupCollapse(event) {
this.$toast.add({ severity: 'success', summary: 'Row Group Collapsed', detail: 'Value: ' + event.data, life: 3000 });
},
calculateCustomerTotal(name) {
let total = 0;
if (this.customers) {
for (let customer of this.customers) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
}
}
};
</script>
<style lang="scss" scoped>
.p-rowgroup-footer td {
font-weight: 700;
}
::v-deep(.p-rowgroup-header) {
span {
font-weight: 700;
}
.p-row-toggler {
vertical-align: middle;
margin-right: 0.25rem;
}
}
</style>

View File

@ -0,0 +1,913 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Scroll</span></h1>
<p>Data scrolling is available horizontally, vertically or both with support for frozen rows and columns.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Vertical</h5>
<DataTable :value="customers1" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"></Column>
</DataTable>
</div>
<div class="card">
<h5>Flexible Scroll</h5>
<p>
Flex scroll feature makes the scrollable viewport section dynamic instead of a fixed value so that it can grow or shrink relative to the parent size of the table. Click the button below to display a maximizable Dialog where data
viewport adjusts itself according to the size changes.
</p>
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
</div>
<Dialog header="Flex Scroll" v-model:visible="dialogVisible" :style="{ width: '75vw' }" :maximizable="true" :modal="true" :contentStyle="{ height: '300px' }">
<DataTable :value="customers1" :scrollable="true" scrollHeight="flex">
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"></Column>
</DataTable>
<template #footer>
<Button label="Ok" icon="pi pi-check" @click="closeDialog" />
</template>
</Dialog>
<div class="card">
<h5>Horizontal and Vertical with Footer</h5>
<DataTable :value="customers2" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both">
<Column field="id" header="Id" footer="Id" style="width: 100px"></Column>
<Column field="name" header="Name" footer="Name" style="width: 200px"></Column>
<Column field="country.name" header="Country" footer="Country" style="width: 200px"></Column>
<Column field="date" header="Date" footer="Date" style="width: 200px"></Column>
<Column field="balance" header="Balance" footer="Balance" style="width: 200px">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
</Column>
<Column field="company" header="Company" footer="Company" style="width: 200px"></Column>
<Column field="status" header="Status" footer="Status" style="width: 200px"></Column>
<Column field="activity" header="Activity" footer="Activity" style="width: 200px"></Column>
<Column field="representative.name" header="Representative" footer="Representative" style="width: 200px"></Column>
</DataTable>
</div>
<div class="card">
<h5>Frozen Rows</h5>
<DataTable :value="unlockedCustomers" :frozenValue="lockedCustomers" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"></Column>
<Column style="flex: 0 0 4rem">
<template #body="{ data, frozenRow, index }">
<Button type="button" :icon="frozenRow ? 'pi pi-lock-open' : 'pi pi-lock'" :disabled="frozenRow ? false : lockedCustomers.length >= 2" class="p-button-sm p-button-text" @click="toggleLock(data, frozenRow, index)" />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Frozen Columns</h5>
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Unfreeze Balance" offLabel="Freeze Balance" style="flex-grow: 1; flex-basis: 12rem" />
<DataTable :value="customers2" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both" class="mt-3">
<Column field="name" header="Name" style="width: 160px" frozen></Column>
<Column field="id" header="Id" style="width: 100px"></Column>
<Column field="name" header="Name" style="width: 200px"></Column>
<Column field="country.name" header="Country" style="width: 200px"></Column>
<Column field="date" header="Date" style="width: 200px"></Column>
<Column field="company" header="Company" style="width: 200px"></Column>
<Column field="status" header="Status" style="width: 200px"></Column>
<Column field="activity" header="Activity" style="width: 200px"></Column>
<Column field="representative.name" header="Representative" style="width: 200px"></Column>
<Column field="balance" header="Balance" style="width: 120px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{ data }">
<span class="font-bold">{{ formatCurrency(data.balance) }}</span>
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Subheader Grouping</h5>
<DataTable :value="customersGrouped" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 200px">
<template #body="slotProps">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{ slotProps.data.country.name }}</span>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{ slotProps.data.status }}</span>
</template>
</Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.data.representative.name }}</span>
</template>
<template #groupfooter="slotProps">
<td style="text-align: right" class="font-bold p-pr-6">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</td>
</template>
</DataTable>
</div>
</div>
<AppDoc name="DataTableScrollDemo" :sources="sources" :service="['CustomerService']" :data="['customers-medium', 'customers-large']" github="datatable/DataTableScrollDemo.vue" />
</div>
</template>
<script>
import CustomerService from '../../service/CustomerService';
export default {
data() {
return {
customers1: null,
customers2: null,
customersGrouped: null,
lockedCustomers: [],
unlockedCustomers: null,
loading: false,
dialogVisible: false,
balanceFrozen: false,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Vertical</h5>
<DataTable :value="customers1" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country.name" header="Country" style="min-width:200px"></Column>
<Column field="representative.name" header="Representative" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px"></Column>
</DataTable>
</div>
<div class="card">
<h5>Flexible Scroll</h5>
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
</div>
<Dialog header="Flex Scroll" v-model:visible="dialogVisible" :style="{width: '75vw'}" :maximizable="true" :modal="true" :contentStyle="{height: '300px'}">
<DataTable :value="customers1" :scrollable="true" scrollHeight="flex">
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country.name" header="Country" style="min-width:200px"></Column>
<Column field="representative.name" header="Representative" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px"></Column>
</DataTable>
<template #footer>
<Button label="Ok" icon="pi pi-check" @click="closeDialog" />
</template>
</Dialog>
<div class="card">
<h5>Horizontal and Vertical with Footer</h5>
<DataTable :value="customers2" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both">
<Column field="id" header="Id" footer="Id" style="width:100px"></Column>
<Column field="name" header="Name" footer="Name" style="width:200px"></Column>
<Column field="country.name" header="Country" footer="Country" style="width:200px"></Column>
<Column field="date" header="Date" footer="Date" style="width:200px"></Column>
<Column field="balance" header="Balance" footer="Balance" style="width:200px">
<template #body="{data}">
{{formatCurrency(data.balance)}}
</template>
</Column>
<Column field="company" header="Company" footer="Company" style="width:200px"></Column>
<Column field="status" header="Status" footer="Status" style="width:200px"></Column>
<Column field="activity" header="Activity" footer="Activity" style="width:200px"></Column>
<Column field="representative.name" header="Representative" footer="Representative" style="width:200px"></Column>
</DataTable>
</div>
<div class="card">
<h5>Frozen Rows</h5>
<DataTable :value="unlockedCustomers" :frozenValue="lockedCustomers" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country.name" header="Country" style="min-width:200px"></Column>
<Column field="representative.name" header="Representative" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px"></Column>
<Column style="flex: 0 0 4rem">
<template #body="{data,frozenRow,index}">
<Button type="button" :icon="frozenRow ? 'pi pi-lock-open' : 'pi pi-lock'" :disabled="frozenRow ? false : lockedCustomers.length >= 2"
class="p-button-sm p-button-text" @click="toggleLock(data,frozenRow,index)"/>
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Frozen Columns</h5>
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Unfreeze Balance" offLabel="Freeze Balance" style="flex-grow:1; flex-basis: 12rem" />
<DataTable :value="customers2" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both" class="mt-3">
<Column field="name" header="Name" style="width:160px" frozen></Column>
<Column field="id" header="Id" style="width:100px"></Column>
<Column field="name" header="Name" style="width:200px"></Column>
<Column field="country.name" header="Country" style="width:200px"></Column>
<Column field="date" header="Date" style="width:200px"></Column>
<Column field="company" header="Company" style="width:200px"></Column>
<Column field="status" header="Status" style="width:200px"></Column>
<Column field="activity" header="Activity" style="width:200px"></Column>
<Column field="representative.name" header="Representative" style="width:200px"></Column>
<Column field="balance" header="Balance" style="width:120px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{data}">
<span class="font-bold">{{formatCurrency(data.balance)}}</span>
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Subheader Grouping</h5>
<DataTable :value="customersGrouped" rowGroupMode="subheader" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country" header="Country" style="min-width:200px">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date" style="min-width:200px"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td style="text-align: right" class="font-bold p-pr-6">Total Customers: {{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</DataTable>
</div>
</div>
</template>
<script>
import CustomerService from './service/CustomerService';
export default {
data() {
return {
customers1: null,
customers2: null,
customersGrouped: null,
lockedCustomers: [],
unlockedCustomers: null,
loading: false,
dialogVisible: false,
balanceFrozen: false
}
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.loading = true;
this.customerService.getCustomersLarge().then(data => {
this.customers1 = data;
this.loading = false;
});
this.customerService.getCustomersMedium().then(data => this.customers2 = data);
this.customerService.getCustomersMedium().then(data => this.unlockedCustomers = data);
this.customerService.getCustomersMedium().then(data => this.customersGrouped = data);
this.lockedCustomers = [
{
id: 5135,
name: "Geraldine Bisset",
country: {
name: "France",
code: "fr"
},
company: "Bisset Group",
status: "proposal",
date: "2019-05-05",
activity: 0,
representative: {
name: "Amy Elsner",
image: "amyelsner.png"
}
}
];
},
methods: {
openDialog() {
this.dialogVisible = true;
},
closeDialog() {
this.dialogVisible = false;
},
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
},
calculateCustomerTotal(name) {
let total = 0;
if (this.customersGrouped) {
for (let customer of this.customersGrouped) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
},
toggleLock(data, frozen, index) {
if (frozen) {
this.lockedCustomers = this.lockedCustomers.filter((c, i) => i !== index);
this.unlockedCustomers.push(data);
}
else {
this.unlockedCustomers = this.unlockedCustomers.filter((c, i) => i !== index);
this.lockedCustomers.push(data);
}
this.unlockedCustomers.sort((val1, val2) => {
return val1.id < val2.id ? -1 : 1;
});
}
}
}
<\\/script>
<style lang="scss" scoped>
::v-deep(.p-datatable-frozen-tbody) {
font-weight: bold;
}
::v-deep(.p-datatable-scrollable .p-frozen-column) {
font-weight: bold;
}
</style>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Vertical</h5>
<DataTable :value="customers1" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country.name" header="Country" style="min-width:200px"></Column>
<Column field="representative.name" header="Representative" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px"></Column>
</DataTable>
</div>
<div class="card">
<h5>Flexible Scroll</h5>
<Button label="Show" icon="pi pi-external-link" @click="openDialog" />
</div>
<Dialog header="Flex Scroll" v-model:visible="dialogVisible" :style="{width: '75vw'}" :maximizable="true" :modal="true" :contentStyle="{height: '300px'}">
<DataTable :value="customers1" :scrollable="true" scrollHeight="flex">
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country.name" header="Country" style="min-width:200px"></Column>
<Column field="representative.name" header="Representative" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px"></Column>
</DataTable>
<template #footer>
<Button label="Ok" icon="pi pi-check" @click="closeDialog" />
</template>
</Dialog>
<div class="card">
<h5>Horizontal and Vertical with Footer</h5>
<DataTable :value="customers2" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both">
<Column field="id" header="Id" footer="Id" style="width:100px"></Column>
<Column field="name" header="Name" footer="Name" style="width:200px"></Column>
<Column field="country.name" header="Country" footer="Country" style="width:200px"></Column>
<Column field="date" header="Date" footer="Date" style="width:200px"></Column>
<Column field="balance" header="Balance" footer="Balance" style="width:200px">
<template #body="{data}">
{{formatCurrency(data.balance)}}
</template>
</Column>
<Column field="company" header="Company" footer="Company" style="width:200px"></Column>
<Column field="status" header="Status" footer="Status" style="width:200px"></Column>
<Column field="activity" header="Activity" footer="Activity" style="width:200px"></Column>
<Column field="representative.name" header="Representative" footer="Representative" style="width:200px"></Column>
</DataTable>
</div>
<div class="card">
<h5>Frozen Rows</h5>
<DataTable :value="unlockedCustomers" :frozenValue="lockedCustomers" :scrollable="true" scrollHeight="400px" :loading="loading">
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country.name" header="Country" style="min-width:200px"></Column>
<Column field="representative.name" header="Representative" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px"></Column>
<Column style="flex: 0 0 4rem">
<template #body="{data,frozenRow,index}">
<Button type="button" :icon="frozenRow ? 'pi pi-lock-open' : 'pi pi-lock'" :disabled="frozenRow ? false : lockedCustomers.length >= 2"
class="p-button-sm p-button-text" @click="toggleLock(data,frozenRow,index)"/>
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Frozen Columns</h5>
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Unfreeze Balance" offLabel="Freeze Balance" style="flex-grow:1; flex-basis: 12rem" />
<DataTable :value="customers2" :scrollable="true" scrollHeight="400px" :loading="loading" scrollDirection="both" class="mt-3">
<Column field="name" header="Name" style="width:160px" frozen></Column>
<Column field="id" header="Id" style="width:100px"></Column>
<Column field="name" header="Name" style="width:200px"></Column>
<Column field="country.name" header="Country" style="width:200px"></Column>
<Column field="date" header="Date" style="width:200px"></Column>
<Column field="company" header="Company" style="width:200px"></Column>
<Column field="status" header="Status" style="width:200px"></Column>
<Column field="activity" header="Activity" style="width:200px"></Column>
<Column field="representative.name" header="Representative" style="width:200px"></Column>
<Column field="balance" header="Balance" style="width:120px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{data}">
<span class="font-bold">{{formatCurrency(data.balance)}}</span>
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Subheader Grouping</h5>
<DataTable :value="customersGrouped" rowGroupMode="subheader" groupRowsBy="representative.name"
sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px">
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width:200px"></Column>
<Column field="country" header="Country" style="min-width:200px">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</Column>
<Column field="company" header="Company" style="min-width:200px"></Column>
<Column field="status" header="Status" style="min-width:200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</Column>
<Column field="date" header="Date" style="min-width:200px"></Column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td style="text-align: right" class="font-bold p-pr-6">Total Customers: {{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import CustomerService from './service/CustomerService';
export default {
setup() {
onMounted(() => {
loading.value = true;
customerService.value.getCustomersLarge().then(data => {
customers1.value = data;
loading.value = false;
});
customerService.value.getCustomersMedium().then(data => customers2.value = data);
customerService.value.getCustomersMedium().then(data => unlockedCustomers.value = data);
customerService.value.getCustomersMedium().then(data => customersGrouped.value = data);
lockedCustomers.value = [
{
id: 5135,
name: "Geraldine Bisset",
country: {
name: "France",
code: "fr"
},
company: "Bisset Group",
status: "proposal",
date: "2019-05-05",
activity: 0,
representative: {
name: "Amy Elsner",
image: "amyelsner.png"
}
}
];
})
const customers1 = ref();
const customers2 = ref();
const customersGrouped = ref();
const lockedCustomers = ref([]);
const unlockedCustomers = ref();
const loading = ref(false);
const dialogVisible = ref(false);
const balanceFrozen = ref(false);
const customerService = ref(new CustomerService());
const openDialog = () => {
dialogVisible.value = true;
};
const closeDialog = () => {
dialogVisible.value = false;
};
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
const calculateCustomerTotal = (name) => {
let total = 0;
if (customersGrouped.value) {
for (let customer of customersGrouped.value) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
};
const toggleLock = (data, frozen, index) => {
if (frozen) {
lockedCustomers.value = lockedCustomers.value.filter((c, i) => i !== index);
unlockedCustomers.value.push(data);
}
else {
unlockedCustomers.value = unlockedCustomers.value.filter((c, i) => i !== index);
lockedCustomers.value.push(data);
}
unlockedCustomers.value.sort((val1, val2) => {
return val1.id < val2.id ? -1 : 1;
});
}
return { customers1, customers2, customersGrouped, lockedCustomers, unlockedCustomers,
loading, dialogVisible, balanceFrozen, openDialog, closeDialog, formatCurrency,
calculateCustomerTotal, toggleLock }
}
}
<\\/script>
<style lang="scss" scoped>
::v-deep(.p-datatable-frozen-tbody) {
font-weight: bold;
}
::v-deep(.p-datatable-scrollable .p-frozen-column) {
font-weight: bold;
}
</style>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/dialog/dialog.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/togglebutton/togglebutton.min.js"><\\/script>
<script src="./CustomerService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<h5>Vertical</h5>
<p-datatable :value="customers1" :scrollable="true" scroll-height="400px" :loading="loading">
<p-column field="name" header="Name" style="min-width:200px"></p-column>
<p-column field="country.name" header="Country" style="min-width:200px"></p-column>
<p-column field="representative.name" header="Representative" style="min-width:200px"></p-column>
<p-column field="status" header="Status" style="min-width:200px"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Flexible Scroll</h5>
<p-button label="Show" icon="pi pi-external-link" @click="openDialog"></p-button>
</div>
<p-dialog header="Flex Scroll" v-model:visible="dialogVisible" :style="{width: '75vw'}" :maximizable="true" :modal="true" :content-style="{height: '300px'}">
<p-datatable :value="customers1" :scrollable="true" scroll-height="flex">
<p-column field="name" header="Name" style="min-width:200px"></p-column>
<p-column field="country.name" header="Country" style="min-width:200px"></p-column>
<p-column field="representative.name" header="Representative" style="min-width:200px"></p-column>
<p-column field="status" header="Status" style="min-width:200px"></p-column>
</p-datatable>
<template #footer>
<p-button label="Ok" icon="pi pi-check" @click="closeDialog"></p-button>
</template>
</p-dialog>
<div class="card">
<h5>Horizontal and Vertical with Footer</h5>
<p-datatable :value="customers2" :scrollable="true" scroll-height="400px" :loading="loading" scroll-direction="both">
<p-column field="id" header="Id" footer="Id" style="width:100px"></p-column>
<p-column field="name" header="Name" footer="Name" style="width:200px"></p-column>
<p-column field="country.name" header="Country" footer="Country" style="width:200px"></p-column>
<p-column field="date" header="Date" footer="Date" style="width:200px"></p-column>
<p-column field="balance" header="Balance" footer="Balance" style="width:200px">
<template #body="{data}">
{{formatCurrency(data.balance)}}
</template>
</p-column>
<p-column field="company" header="Company" footer="Company" style="width:200px"></p-column>
<p-column field="status" header="Status" footer="Status" style="width:200px"></p-column>
<p-column field="activity" header="Activity" footer="Activity" style="width:200px"></p-column>
<p-column field="representative.name" header="Representative" footer="Representative" style="width:200px"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Frozen Rows</h5>
<p-datatable :value="unlockedCustomers" :frozen-value="lockedCustomers" :scrollable="true" scroll-height="400px" :loading="loading">
<p-column field="name" header="Name" style="min-width:200px"></p-column>
<p-column field="country.name" header="Country" style="min-width:200px"></p-column>
<p-column field="representative.name" header="Representative" style="min-width:200px"></p-column>
<p-column field="status" header="Status" style="min-width:200px"></p-column>
<p-column style="flex: 0 0 4rem">
<template #body="{data,frozenRow,index}">
<p-button type="button" :icon="frozenRow ? 'pi pi-lock-open' : 'pi pi-lock'" :disabled="frozenRow ? false : lockedCustomers.length >= 2"
class="p-button-sm p-button-text" @click="toggleLock(data,frozenRow,index)"></p-button>
</template>
</p-column>
</p-datatable>
</div>
<div class="card">
<h5>Frozen Columns</h5>
<p-togglebutton v-model="balanceFrozen" on-icon="pi pi-lock" off-icon="pi pi-lock-open" on-label="Unfreeze Balance" off-label="Freeze Balance" style="flex-grow:1; flex-basis: 12rem"></p-togglebutton>
<p-datatable :value="customers2" :scrollable="true" scroll-height="400px" :loading="loading" scroll-direction="both" class="mt-3">
<p-column field="name" header="Name" style="width:160px" frozen></p-column>
<p-column field="id" header="Id" style="width:100px"></p-column>
<p-column field="name" header="Name" style="width:200px"></p-column>
<p-column field="country.name" header="Country" style="width:200px"></p-column>
<p-column field="date" header="Date" style="width:200px"></p-column>
<p-column field="company" header="Company" style="width:200px"></p-column>
<p-column field="status" header="Status" style="width:200px"></p-column>
<p-column field="activity" header="Activity" style="width:200px"></p-column>
<p-column field="representative.name" header="Representative" style="width:200px"></p-column>
<p-column field="balance" header="Balance" style="width:120px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{data}">
<span class="font-bold">{{formatCurrency(data.balance)}}</span>
</template>
</p-column>
</p-datatable>
</div>
<div class="card">
<h5>Subheader Grouping</h5>
<p-datatable :value="customersGrouped" row-group-mode="subheader" group-rows-by="representative.name"
sort-mode="single" sort-field="representative.name" :sort-order="1" scrollable scroll-height="400px">
<p-column field="representative.name" header="Representative"></p-column>
<p-column field="name" header="Name" style="min-width:200px"></p-column>
<p-column field="country" header="Country" style="min-width:200px">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="30" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
</p-column>
<p-column field="company" header="Company" style="min-width:200px"></p-column>
<p-column field="status" header="Status" style="min-width:200px">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
</p-column>
<p-column field="date" header="Date" style="min-width:200px"></p-column>
<template #groupheader="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="32" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #groupfooter="slotProps">
<td style="text-align: right" class="font-bold p-pr-6">Total Customers: {{calculateCustomerTotal(slotProps.data.representative.name)}}</td>
</template>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
loading.value = true;
customerService.value.getCustomersLarge().then(data => {
customers1.value = data;
loading.value = false;
});
customerService.value.getCustomersMedium().then(data => customers2.value = data);
customerService.value.getCustomersMedium().then(data => unlockedCustomers.value = data);
customerService.value.getCustomersMedium().then(data => customersGrouped.value = data);
lockedCustomers.value = [
{
id: 5135,
name: "Geraldine Bisset",
country: {
name: "France",
code: "fr"
},
company: "Bisset Group",
status: "proposal",
date: "2019-05-05",
activity: 0,
representative: {
name: "Amy Elsner",
image: "amyelsner.png"
}
}
];
})
const customers1 = ref();
const customers2 = ref();
const customersGrouped = ref();
const lockedCustomers = ref([]);
const unlockedCustomers = ref();
const loading = ref(false);
const dialogVisible = ref(false);
const balanceFrozen = ref(false);
const customerService = ref(new CustomerService());
const openDialog = () => {
dialogVisible.value = true;
};
const closeDialog = () => {
dialogVisible.value = false;
};
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
const calculateCustomerTotal = (name) => {
let total = 0;
if (customersGrouped.value) {
for (let customer of customersGrouped.value) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
};
const toggleLock = (data, frozen, index) => {
if (frozen) {
lockedCustomers.value = lockedCustomers.value.filter((c, i) => i !== index);
unlockedCustomers.value.push(data);
}
else {
unlockedCustomers.value = unlockedCustomers.value.filter((c, i) => i !== index);
lockedCustomers.value.push(data);
}
unlockedCustomers.value.sort((val1, val2) => {
return val1.id < val2.id ? -1 : 1;
});
}
return { customers1, customers2, customersGrouped, lockedCustomers, unlockedCustomers,
loading, dialogVisible, balanceFrozen, openDialog, closeDialog, formatCurrency,
calculateCustomerTotal, toggleLock }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-dialog": primevue.dialog,
"p-button": primevue.button,
"p-togglebutton": primevue.togglebutton
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.p-datatable-frozen-tbody {
font-weight: bold;
}
.p-datatable-scrollable .p-frozen-column {
font-weight: bold;
}
</style>
`
}
}
};
},
customerService: null,
created() {
this.customerService = new CustomerService();
},
mounted() {
this.loading = true;
this.customerService.getCustomersLarge().then((data) => {
this.customers1 = data;
this.loading = false;
});
this.customerService.getCustomersMedium().then((data) => (this.customers2 = data));
this.customerService.getCustomersMedium().then((data) => (this.unlockedCustomers = data));
this.customerService.getCustomersMedium().then((data) => (this.customersGrouped = data));
this.lockedCustomers = [
{
id: 5135,
name: 'Geraldine Bisset',
country: {
name: 'France',
code: 'fr'
},
company: 'Bisset Group',
status: 'proposal',
date: '2019-05-05',
activity: 0,
representative: {
name: 'Amy Elsner',
image: 'amyelsner.png'
}
}
];
},
methods: {
openDialog() {
this.dialogVisible = true;
},
closeDialog() {
this.dialogVisible = false;
},
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
},
calculateCustomerTotal(name) {
let total = 0;
if (this.customersGrouped) {
for (let customer of this.customersGrouped) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
},
toggleLock(data, frozen, index) {
if (frozen) {
this.lockedCustomers = this.lockedCustomers.filter((c, i) => i !== index);
this.unlockedCustomers.push(data);
} else {
this.unlockedCustomers = this.unlockedCustomers.filter((c, i) => i !== index);
this.lockedCustomers.push(data);
}
this.unlockedCustomers.sort((val1, val2) => {
return val1.id < val2.id ? -1 : 1;
});
}
}
};
</script>
<style lang="scss" scoped>
::v-deep(.p-datatable-frozen-tbody) {
font-weight: bold;
}
::v-deep(.p-datatable-scrollable .p-frozen-column) {
font-weight: bold;
}
</style>

View File

@ -0,0 +1,461 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Selection</span></h1>
<p>DataTable provides single and multiple selection modes based on row click or using radio button and checkbox elements.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Single</h5>
<p>In single mode, a row is selected on click event of a row. If the row is already selected then the row gets unselected.</p>
<DataTable :value="products" v-model:selection="selectedProduct1" selectionMode="single" dataKey="id" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Multiple</h5>
<p>
In multiple mode, selection binding should be an array. For touch enabled devices, selection is managed by tapping and for other devices metakey or shiftkey are required. Setting metaKeySelection property as false enables multiple
selection without meta key.
</p>
<DataTable :value="products" v-model:selection="selectedProducts1" selectionMode="multiple" dataKey="id" responsiveLayout="scroll">
<template #header> Multiple Selection with MetaKey </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
<DataTable :value="products" v-model:selection="selectedProducts2" selectionMode="multiple" dataKey="id" :metaKeySelection="false" style="margin-top: 2em" responsiveLayout="scroll">
<template #header> Multiple Selection without MetaKey </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Events</h5>
<p>row-select and row-unselects are available as selection events.</p>
<DataTable :value="products" v-model:selection="selectedProduct2" selectionMode="single" dataKey="id" @row-select="onRowSelect" @row-unselect="onRowUnselect" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>RadioButton</h5>
<p>Single selection can also be handled using radio buttons by enabling the selectionMode property of column as "single".</p>
<DataTable :value="products" v-model:selection="selectedProduct3" dataKey="id" responsiveLayout="scroll">
<Column selectionMode="single" headerStyle="width: 3em"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Checkbox</h5>
<DataTable :value="products" v-model:selection="selectedProducts3" dataKey="id" responsiveLayout="scroll">
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableSelectionDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableSelectionDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
selectedProduct1: null,
selectedProduct2: null,
selectedProduct3: null,
selectedProducts1: null,
selectedProducts2: null,
selectedProducts3: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Toast />
<div class="card">
<h5>Single</h5>
<DataTable :value="products" v-model:selection="selectedProduct1" selectionMode="single" dataKey="id" responsiveLayout="scroll" >
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Multiple</h5>
<DataTable :value="products" v-model:selection="selectedProducts1" selectionMode="multiple" dataKey="id" responsiveLayout="scroll" >
<template #header>
Multiple Selection with MetaKey
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
<DataTable :value="products" v-model:selection="selectedProducts2" selectionMode="multiple" dataKey="id" :metaKeySelection="false" style="margin-top: 2em" responsiveLayout="scroll" >
<template #header>
Multiple Selection without MetaKey
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Events</h5>
<DataTable :value="products" v-model:selection="selectedProduct2" selectionMode="single" dataKey="id"
@rowSelect="onRowSelect" @rowUnselect="onRowUnselect" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>RadioButton</h5>
<DataTable :value="products" v-model:selection="selectedProduct3" dataKey="id" responsiveLayout="scroll" >
<Column selectionMode="single" headerStyle="width: 3em"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Checkbox</h5>
<DataTable :value="products" v-model:selection="selectedProducts3" dataKey="id" responsiveLayout="scroll" >
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null,
selectedProduct1: null,
selectedProduct2: null,
selectedProduct3: null,
selectedProducts1: null,
selectedProducts2: null,
selectedProducts3: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
onRowSelect(event) {
this.$toast.add({severity: 'info', summary: 'Product Selected', detail: 'Name: ' + event.data.name, life: 3000});
},
onRowUnselect(event) {
this.$toast.add({severity: 'warn', summary: 'Product Unselected', detail: 'Name: ' + event.data.name, life: 3000});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Toast />
<div class="card">
<h5>Single</h5>
<DataTable :value="products" v-model:selection="selectedProduct1" selectionMode="single" dataKey="id" responsiveLayout="scroll" >
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Multiple</h5>
<DataTable :value="products" v-model:selection="selectedProducts1" selectionMode="multiple" dataKey="id" responsiveLayout="scroll" >
<template #header>
Multiple Selection with MetaKey
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
<DataTable :value="products" v-model:selection="selectedProducts2" selectionMode="multiple" dataKey="id" :metaKeySelection="false" style="margin-top: 2em" responsiveLayout="scroll" >
<template #header>
Multiple Selection without MetaKey
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Events</h5>
<DataTable :value="products" v-model:selection="selectedProduct2" selectionMode="single" dataKey="id"
@rowSelect="onRowSelect" @rowUnselect="onRowUnselect" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>RadioButton</h5>
<DataTable :value="products" v-model:selection="selectedProduct3" dataKey="id" responsiveLayout="scroll" >
<Column selectionMode="single" headerStyle="width: 3em"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<h5>Checkbox</h5>
<DataTable :value="products" v-model:selection="selectedProducts3" dataKey="id" responsiveLayout="scroll" >
<Column selectionMode="multiple" headerStyle="width: 3em"></Column>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { useToast } from 'primevue/usetoast';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const toast = useToast();
const products = ref();
const selectedProduct1 = ref();
const selectedProduct2 = ref();
const selectedProduct3 = ref();
const selectedProducts1 = ref();
const selectedProducts2 = ref();
const selectedProducts3 = ref();
const productService = ref(new ProductService());
const onRowSelect = (event) => {
toast.add({severity: 'info', summary: 'Product Selected', detail: 'Name: ' + event.data.name, life: 3000});
};
const onRowUnselect = (event) => {
toast.add({severity: 'warn', summary: 'Product Unselected', detail: 'Name: ' + event.data.name, life: 3000});
};
return { products, selectedProduct1, selectedProduct2, selectedProduct3, selectedProducts1, selectedProducts2, selectedProducts3, onRowSelect, onRowUnselect}
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/usetoast/usetoast.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-toast></p-toast>
<div class="card">
<h5>Single</h5>
<p-datatable :value="products" v-model:selection="selectedProduct1" selection-mode="single" dataKey="id" responsive-layout="scroll" >
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Multiple</h5>
<p-datatable :value="products" v-model:selection="selectedProducts1" selection-mode="multiple" dataKey="id" responsive-layout="scroll" >
<template #header>
Multiple Selection with MetaKey
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
<p-datatable :value="products" v-model:selection="selectedProducts2" selection-mode="multiple" dataKey="id" :meta-key-selection="false" style="margin-top: 2em" responsive-layout="scroll" >
<template #header>
Multiple Selection without MetaKey
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Events</h5>
<p-datatable :value="products" v-model:selection="selectedProduct2" selection-mode="single" dataKey="id"
@row-select="onRowSelect" @row-unselect="onRowUnselect" responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>RadioButton</h5>
<p-datatable :value="products" v-model:selection="selectedProduct3" dataKey="id" responsive-layout="scroll" >
<p-column selection-mode="single" header-style="width: 3em"></p-column>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Checkbox</h5>
<p-datatable :value="products" v-model:selection="selectedProducts3" dataKey="id" responsive-layout="scroll" >
<p-column selection-mode="multiple" header-style="width: 3em"></p-column>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const { useToast } = primevue.usetoast;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const toast = useToast();
const products = ref();
const selectedProduct1 = ref();
const selectedProduct2 = ref();
const selectedProduct3 = ref();
const selectedProducts1 = ref();
const selectedProducts2 = ref();
const selectedProducts3 = ref();
const productService = ref(new ProductService());
const onRowSelect = (event) => {
toast.add({severity: 'info', summary: 'Product Selected', detail: 'Name: ' + event.data.name, life: 3000});
};
const onRowUnselect = (event) => {
toast.add({severity: 'warn', summary: 'Product Unselected', detail: 'Name: ' + event.data.name, life: 3000});
};
return { products, selectedProduct1, selectedProduct2, selectedProduct3, selectedProducts1, selectedProducts2, selectedProducts3, onRowSelect, onRowUnselect}
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-toast": primevue.toast
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
onRowSelect(event) {
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: 'Name: ' + event.data.name, life: 3000 });
},
onRowUnselect(event) {
this.$toast.add({ severity: 'warn', summary: 'Product Unselected', detail: 'Name: ' + event.data.name, life: 3000 });
}
}
};
</script>

View File

@ -0,0 +1,260 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Size</span></h1>
<p>In addition to a regular table, alternatives with alternative sizes are available.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" class="p-datatable-sm" responsiveLayout="scroll">
<template #header> Small Table </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header> Normal Table </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" class="p-datatable-lg" responsiveLayout="scroll">
<template #header> Large Table </template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableSizeDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableSizeDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<DataTable :value="products" class="p-datatable-sm" responsiveLayout="scroll">
<template #header>
Small Table
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
Normal Table
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" class="p-datatable-lg" responsiveLayout="scroll">
<template #header>
Large Table
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<DataTable :value="products" class="p-datatable-sm" responsiveLayout="scroll">
<template #header>
Small Table
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
Normal Table
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
<div class="card">
<DataTable :value="products" class="p-datatable-lg" responsiveLayout="scroll">
<template #header>
Large Table
</template>
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<p-datatable :value="products" class="p-datatable-sm" responsive-layout="scroll">
<template #header>
Small Table
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<div class="card">
<p-datatable :value="products" responsive-layout="scroll">
<template #header>
Normal Table
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<div class="card">
<p-datatable :value="products" class="p-datatable-lg" responsive-layout="scroll">
<template #header>
Large Table
</template>
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></Column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
}
};
</script>

View File

@ -0,0 +1,381 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Sort</span></h1>
<p>Enabling sortable property on a column is enough to make a column sortable. Multiple column sorting is enabled using sortMode property and used with metaKey.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Single Column</h5>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Multiple Columns</h5>
<p>Use metakey to add a column to the sort selection.</p>
<DataTable :value="products" sortMode="multiple" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Presort</h5>
<DataTable :value="products" sortField="category" :sortOrder="-1" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Removable Sort</h5>
<DataTable :value="products" removableSort responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableSortDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableSortDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Single Column</h5>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Multiple Columns</h5>
<DataTable :value="products" sortMode="multiple" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Presort</h5>
<DataTable :value="products" sortField="category" :sortOrder="-1" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Removable Sort</h5>
<DataTable :value="products" removableSort responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Single Column</h5>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Multiple Columns</h5>
<DataTable :value="products" sortMode="multiple" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Presort</h5>
<DataTable :value="products" sortField="category" :sortOrder="-1" responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
<div class="card">
<h5>Removable Sort</h5>
<DataTable :value="products" removableSort responsiveLayout="scroll">
<Column field="code" header="Code" :sortable="true"></Column>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="category" header="Category" :sortable="true"></Column>
<Column field="quantity" header="Quantity" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { products, formatCurrency }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<h5>Single Column</h5>
<p-datatable :value="products" responsive-layout="scroll">
<p-column field="code" header="Code" :sortable="true"></p-column>
<p-column field="name" header="Name" :sortable="true"></p-column>
<p-column field="category" header="Category" :sortable="true"></p-column>
<p-column field="quantity" header="Quantity" :sortable="true"></p-column>
<p-column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</p-column>
</p-datatable>
</div>
<div class="card">
<h5>Multiple Columns</h5>
<p-datatable :value="products" sort-mode="multiple" responsive-layout="scroll">
<p-column field="code" header="Code" :sortable="true"></p-column>
<p-column field="name" header="Name" :sortable="true"></p-column>
<p-column field="category" header="Category" :sortable="true"></p-column>
<p-column field="quantity" header="Quantity" :sortable="true"></p-column>
<p-column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</p-column>
</p-datatable>
</div>
<div class="card">
<h5>Presort</h5>
<p-datatable :value="products" sort-field="category" :sort-order="-1" responsive-layout="scroll">
<p-column field="code" header="Code" :sortable="true"></p-column>
<p-column field="name" header="Name" :sortable="true"></p-column>
<p-column field="category" header="Category" :sortable="true"></p-column>
<p-column field="quantity" header="Quantity" :sortable="true"></p-column>
<p-column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</p-column>
</p-datatable>
</div>
<div class="card">
<h5>Removable Sort</h5>
<p-datatable :value="products" removable-sort responsive-layout="scroll">
<p-column field="code" header="Code" :sortable="true"></p-column>
<p-column field="name" header="Name" :sortable="true"></p-column>
<p-column field="category" header="Category" :sortable="true"></p-column>
<p-column field="quantity" header="Quantity" :sortable="true"></p-column>
<p-column field="price" header="Price" :sortable="true">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { products, formatCurrency }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
}
};
</script>

View File

@ -0,0 +1,722 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>State</span></h1>
<p>Stateful table allows keeping the state such as page, sort and filtering either at local storage or session storage so that when the page is visited again, table would render the data using its last settings.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Session Storage</h5>
<DataTable
:value="customers"
:paginator="true"
:rows="10"
v-model:filters="filters1"
v-model:selection="selectedCustomer1"
selectionMode="single"
dataKey="id"
stateStorage="session"
stateKey="dt-state-demo-session"
responsiveLayout="scroll"
>
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters1['global'].value" placeholder="Global Search" />
</span>
</template>
<Column field="name" header="Name" :sortable="true" style="width: 25%">
<template #filter>
<InputText type="text" v-model="filters1['name']" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" :sortable="true" sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width: 25%">
<template #body="slotProps">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{ slotProps.data.country.name }}</span>
</template>
<template #filter>
<InputText type="text" v-model="filters1['country.name']" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Representative" :sortable="true" sortField="representative.name" filterField="representative.name" filterMatchMode="in" style="width: 25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.data.representative.name }}</span>
</template>
<template #filter>
<MultiSelect v-model="filters1['representative.name']" :options="representatives" optionLabel="name" optionValue="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" :src="'demo/images/avatar/' + slotProps.option.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :sortable="true" filterMatchMode="equals" style="width: 25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{ slotProps.data.status }}</span>
</template>
<template #filter>
<Dropdown v-model="filters1['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :showClear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{ slotProps.option }}</span>
</template>
</Dropdown>
</template>
</Column>
<template #empty> No customers found. </template>
</DataTable>
</div>
<div class="card">
<h5>Local Storage</h5>
<DataTable
:value="customers"
:paginator="true"
:rows="10"
v-model:filters="filters2"
v-model:selection="selectedCustomer2"
selectionMode="single"
dataKey="id"
stateStorage="local"
stateKey="dt-state-demo-local"
responsiveLayout="scroll"
>
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters2['global'].value" placeholder="Global Search" />
</span>
</template>
<Column field="name" header="Name" :sortable="true" style="width: 25%">
<template #filter>
<InputText type="text" v-model="filters2['name']" class="p-column-filter" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" :sortable="true" sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width: 25%">
<template #body="slotProps">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.data.country.code" width="30" />
<span class="image-text">{{ slotProps.data.country.name }}</span>
</template>
<template #filter>
<InputText type="text" v-model="filters2['country.name']" class="p-column-filter" placeholder="Search by country" />
</template>
</Column>
<Column header="Representative" :sortable="true" sortField="representative.name" filterField="representative.name" filterMatchMode="in" style="width: 25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" :src="'demo/images/avatar/' + slotProps.data.representative.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.data.representative.name }}</span>
</template>
<template #filter>
<MultiSelect v-model="filters2['representative.name']" :options="representatives" optionLabel="name" optionValue="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" :src="'demo/images/avatar/' + slotProps.option.image" width="32" style="vertical-align: middle" />
<span class="image-text">{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :sortable="true" filterMatchMode="equals" style="width: 25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{ slotProps.data.status }}</span>
</template>
<template #filter>
<Dropdown v-model="filters2['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :showClear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{ slotProps.option }}</span>
</template>
</Dropdown>
</template>
</Column>
<template #empty> No customers found. </template>
</DataTable>
</div>
</div>
<AppDoc name="DataTableStateDemo" :sources="sources" :service="['CustomerService']" :data="['customers-medium']" github="datatable/DataTableStateDemo.vue" />
</div>
</template>
<script>
import { FilterMatchMode } from 'primevue/api';
import CustomerService from '../../service/CustomerService';
export default {
data() {
return {
customers: null,
selectedCustomer1: null,
selectedCustomer2: null,
filters1: {},
filters2: {},
loading: true,
representatives: [
{ name: 'Amy Elsner', image: 'amyelsner.png' },
{ name: 'Anna Fali', image: 'annafali.png' },
{ name: 'Asiya Javayant', image: 'asiyajavayant.png' },
{ name: 'Bernardo Dominic', image: 'bernardodominic.png' },
{ name: 'Elwin Sharvill', image: 'elwinsharvill.png' },
{ name: 'Ioni Bowcher', image: 'ionibowcher.png' },
{ name: 'Ivan Magalhaes', image: 'ivanmagalhaes.png' },
{ name: 'Onyama Limba', image: 'onyamalimba.png' },
{ name: 'Stephen Shaw', image: 'stephenshaw.png' },
{ name: 'XuXue Feng', image: 'xuxuefeng.png' }
],
statuses: ['unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'],
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Session Storage</h5>
<DataTable :value="customers" :paginator="true" :rows="10" v-model:filters="filters1"
v-model:selection="selectedCustomer1" selectionMode="single" dataKey="id"
stateStorage="session" stateKey="dt-state-demo-session" responsiveLayout="scroll">
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters1['global'].value" placeholder="Global Search" />
</span>
</template>
<Column field="name" header="Name" :sortable="true" style="width:25%">
<template #filter>
<InputText type="text" v-model="filters1['name']" class="p-column-filter" placeholder="Search by name"/>
</template>
</Column>
<Column header="Country" :sortable="true" sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width:25%">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
<template #filter>
<InputText type="text" v-model="filters1['country.name']" class="p-column-filter" placeholder="Search by country"/>
</template>
</Column>
<Column header="Representative" :sortable="true" sortField="representative.name" filterField="representative.name" filterMatchMode="in" style="width:25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #filter>
<MultiSelect v-model="filters1['representative.name']" :options="representatives" optionLabel="name" optionValue="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.option.name}}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :sortable="true" filterMatchMode="equals" style="width:25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
<template #filter>
<Dropdown v-model="filters1['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :showClear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
</template>
</Dropdown>
</template>
</Column>
<template #empty>
No customers found.
</template>
</DataTable>
</div>
<div class="card">
<h5>Local Storage</h5>
<DataTable :value="customers" :paginator="true" :rows="10" v-model:filters="filters2"
v-model:selection="selectedCustomer2" selectionMode="single" dataKey="id"
stateStorage="local" stateKey="dt-state-demo-local" responsiveLayout="scroll">
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters2['global'].value" placeholder="Global Search" />
</span>
</template>
<Column field="name" header="Name" :sortable="true" style="width:25%">
<template #filter>
<InputText type="text" v-model="filters2['name']" class="p-column-filter" placeholder="Search by name"/>
</template>
</Column>
<Column header="Country" :sortable="true" sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width:25%">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
<template #filter>
<InputText type="text" v-model="filters2['country.name']" class="p-column-filter" placeholder="Search by country"/>
</template>
</Column>
<Column header="Representative" :sortable="true" sortField="representative.name" filterField="representative.name" filterMatchMode="in" style="width:25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #filter>
<MultiSelect v-model="filters2['representative.name']" :options="representatives" optionLabel="name" optionValue="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.option.name}}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :sortable="true" filterMatchMode="equals" style="width:25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
<template #filter>
<Dropdown v-model="filters2['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :showClear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
</template>
</Dropdown>
</template>
</Column>
<template #empty>
No customers found.
</template>
</DataTable>
</div>
</div>
</template>
<script>
import { FilterMatchMode } from 'primevue/api';
import CustomerService from './service/CustomerService';
export default {
data() {
return {
customers: null,
selectedCustomer1: null,
selectedCustomer2: null,
filters1: {},
filters2: {},
loading: true,
representatives: [
{name: "Amy Elsner", image: 'amyelsner.png'},
{name: "Anna Fali", image: 'annafali.png'},
{name: "Asiya Javayant", image: 'asiyajavayant.png'},
{name: "Bernardo Dominic", image: 'bernardodominic.png'},
{name: "Elwin Sharvill", image: 'elwinsharvill.png'},
{name: "Ioni Bowcher", image: 'ionibowcher.png'},
{name: "Ivan Magalhaes",image: 'ivanmagalhaes.png'},
{name: "Onyama Limba", image: 'onyamalimba.png'},
{name: "Stephen Shaw", image: 'stephenshaw.png'},
{name: "XuXue Feng", image: 'xuxuefeng.png'}
],
statuses: [
'unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'
]
}
},
customerService: null,
created() {
this.customerService = new CustomerService();
this.initFilters1();
this.initFilters2();
},
mounted() {
this.customerService.getCustomersMedium().then(data => this.customers = data);
},
methods: {
initFilters1() {
this.filters1 = {
'global': {value: null, matchMode: FilterMatchMode.CONTAINS}
}
},
initFilters2() {
this.filters2 = {
'global': {value: null, matchMode: FilterMatchMode.CONTAINS}
}
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Session Storage</h5>
<DataTable :value="customers" :paginator="true" :rows="10" v-model:filters="filters1"
v-model:selection="selectedCustomer1" selectionMode="single" dataKey="id"
stateStorage="session" stateKey="dt-state-demo-session" responsiveLayout="scroll">
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters1['global'].value" placeholder="Global Search" />
</span>
</template>
<Column field="name" header="Name" :sortable="true" style="width:25%">
<template #filter>
<InputText type="text" v-model="filters1['name']" class="p-column-filter" placeholder="Search by name"/>
</template>
</Column>
<Column header="Country" :sortable="true" sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width:25%">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
<template #filter>
<InputText type="text" v-model="filters1['country.name']" class="p-column-filter" placeholder="Search by country"/>
</template>
</Column>
<Column header="Representative" :sortable="true" sortField="representative.name" filterField="representative.name" filterMatchMode="in" style="width:25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #filter>
<MultiSelect v-model="filters1['representative.name']" :options="representatives" optionLabel="name" optionValue="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.option.name}}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :sortable="true" filterMatchMode="equals" style="width:25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
<template #filter>
<Dropdown v-model="filters1['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :showClear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
</template>
</Dropdown>
</template>
</Column>
<template #empty>
No customers found.
</template>
</DataTable>
</div>
<div class="card">
<h5>Local Storage</h5>
<DataTable :value="customers" :paginator="true" :rows="10" v-model:filters="filters2"
v-model:selection="selectedCustomer2" selectionMode="single" dataKey="id"
stateStorage="local" stateKey="dt-state-demo-local" responsiveLayout="scroll">
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search" />
<InputText v-model="filters2['global'].value" placeholder="Global Search" />
</span>
</template>
<Column field="name" header="Name" :sortable="true" style="width:25%">
<template #filter>
<InputText type="text" v-model="filters2['name']" class="p-column-filter" placeholder="Search by name"/>
</template>
</Column>
<Column header="Country" :sortable="true" sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width:25%">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
<template #filter>
<InputText type="text" v-model="filters2['country.name']" class="p-column-filter" placeholder="Search by country"/>
</template>
</Column>
<Column header="Representative" :sortable="true" sortField="representative.name" filterField="representative.name" filterMatchMode="in" style="width:25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #filter>
<MultiSelect v-model="filters2['representative.name']" :options="representatives" optionLabel="name" optionValue="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.option.name}}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column field="status" header="Status" :sortable="true" filterMatchMode="equals" style="width:25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
<template #filter>
<Dropdown v-model="filters2['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :showClear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
</template>
</Dropdown>
</template>
</Column>
<template #empty>
No customers found.
</template>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { FilterMatchMode } from 'primevue/api';
import CustomerService from './service/CustomerService';
export default {
setup() {
onMounted(() => {
customerService.value.getCustomersMedium().then(data => customers.value = data);
})
const customers = ref();
const customerService = ref(new CustomerService());
const selectedCustomer1 = ref();
const selectedCustomer2 = ref();
const filters1 = ref({'global': {value: null, matchMode: FilterMatchMode.CONTAINS}});
const filters2 = ref({'global': {value: null, matchMode: FilterMatchMode.CONTAINS}});
const loading = ref(true);
const representatives = ref([
{name: "Amy Elsner", image: 'amyelsner.png'},
{name: "Anna Fali", image: 'annafali.png'},
{name: "Asiya Javayant", image: 'asiyajavayant.png'},
{name: "Bernardo Dominic", image: 'bernardodominic.png'},
{name: "Elwin Sharvill", image: 'elwinsharvill.png'},
{name: "Ioni Bowcher", image: 'ionibowcher.png'},
{name: "Ivan Magalhaes",image: 'ivanmagalhaes.png'},
{name: "Onyama Limba", image: 'onyamalimba.png'},
{name: "Stephen Shaw", image: 'stephenshaw.png'},
{name: "XuXue Feng", image: 'xuxuefeng.png'}
]);
const statuses = ref([
'unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'
]);
return { customers, customerService, selectedCustomer1, selectedCustomer2, filters1, filters2, loading, representatives, statuses }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/multiselect/multiselect.min.js"><\\/script>
<script src="./CustomerService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<h5>Session Storage</h5>
<p-datatable :value="customers" :paginator="true" :rows="10" v-model:filters="filters1"
v-model:selection="selectedCustomer1" selection-mode="single" data-key="id"
state-storage="session" state-key="dt-state-demo-session" responsive-layout="scroll">
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<p-inputtext v-model="filters1['global'].value" placeholder="Global Search"></p-inputtext>
</span>
</template>
<p-column field="name" header="Name" :sortable="true" style="width:25%">
<template #filter>
<p-inputtext type="text" v-model="filters1['name']" class="p-column-filter" placeholder="Search by name"></p-inputtext>
</template>
</p-column>
<p-column header="Country" :sortable="true" sort-field="country.name" filter-field="country.name" filter-match-mode="contains" style="width:25%">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
<template #filter>
<p-inputtext type="text" v-model="filters1['country.name']" class="p-column-filter" placeholder="Search by country"></p-inputtext>
</template>
</p-column>
<p-column header="Representative" :sortable="true" sort-field="representative.name" filter-field="representative.name" filter-match-mode="in" style="width:25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #filter>
<p-multiselect v-model="filters1['representative.name']" :options="representatives" option-label="name" option-value="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.option.name}}</span>
</div>
</template>
</p-multiselect>
</template>
</p-column>
<p-column field="status" header="Status" :sortable="true" filter-match-mode="equals" style="width:25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
<template #filter>
<p-dropdown v-model="filters1['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :show-clear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
</template>
</p-dropdown>
</template>
</p-column>
<template #empty>
No customers found.
</template>
</p-datatable>
</div>
<div class="card">
<h5>Local Storage</h5>
<p-datatable :value="customers" :paginator="true" :rows="10" v-model:filters="filters2"
v-model:selection="selectedCustomer2" selection-mode="single" data-key="id"
state-storage="local" state-key="dt-state-demo-local" responsive-layout="scroll">
<template #header>
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<p-inputtext v-model="filters2['global'].value" placeholder="Global Search"></p-inputtext>
</span>
</template>
<p-column field="name" header="Name" :sortable="true" style="width:25%">
<template #filter>
<p-inputtext type="text" v-model="filters2['name']" class="p-column-filter" placeholder="Search by name"></p-inputtext>
</template>
</p-column>
<p-column header="Country" :sortable="true" sortField="country.name" filterField="country.name" filterMatchMode="contains" style="width:25%">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" />
<span class="image-text">{{slotProps.data.country.name}}</span>
</template>
<template #filter>
<p-inputtext type="text" v-model="filters2['country.name']" class="p-column-filter" placeholder="Search by country"></p-inputtext>
</template>
</p-column>
<p-column header="Representative" :sortable="true" sortField="representative.name" filterField="representative.name" filterMatchMode="in" style="width:25%">
<template #body="slotProps">
<img :alt="slotProps.data.representative.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.data.representative.name}}</span>
</template>
<template #filter>
<p-multiselect v-model="filters2['representative.name']" :options="representatives" optionLabel="name" optionValue="name" placeholder="All" class="p-column-filter">
<template #option="slotProps">
<div class="p-multiselect-representative-option">
<img :alt="slotProps.option.name" src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" width="20" style="vertical-align: middle" />
<span class="image-text">{{slotProps.option.name}}</span>
</div>
</template>
</p-multiselect>
</template>
</p-column>
<p-column field="status" header="Status" :sortable="true" filterMatchMode="equals" style="width:25%">
<template #body="slotProps">
<span :class="'customer-badge status-' + slotProps.data.status">{{slotProps.data.status}}</span>
</template>
<template #filter>
<p-dropdown v-model="filters2['status']" :options="statuses" placeholder="Select a Status" class="p-column-filter" :showClear="true">
<template #option="slotProps">
<span :class="'customer-badge status-' + slotProps.option">{{slotProps.option}}</span>
</template>
</p-dropdown>
</template>
</p-column>
<template #empty>
No customers found.
</template>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const { FilterMatchMode } = primevue.api;
const App = {
setup() {
onMounted(() => {
customerService.value.getCustomersMedium().then(data => customers.value = data);
})
const customers = ref();
const customerService = ref(new CustomerService());
const selectedCustomer1 = ref();
const selectedCustomer2 = ref();
const filters1 = ref({'global': {value: null, matchMode: FilterMatchMode.CONTAINS}});
const filters2 = ref({'global': {value: null, matchMode: FilterMatchMode.CONTAINS}});
const loading = ref(true);
const representatives = ref([
{name: "Amy Elsner", image: 'amyelsner.png'},
{name: "Anna Fali", image: 'annafali.png'},
{name: "Asiya Javayant", image: 'asiyajavayant.png'},
{name: "Bernardo Dominic", image: 'bernardodominic.png'},
{name: "Elwin Sharvill", image: 'elwinsharvill.png'},
{name: "Ioni Bowcher", image: 'ionibowcher.png'},
{name: "Ivan Magalhaes",image: 'ivanmagalhaes.png'},
{name: "Onyama Limba", image: 'onyamalimba.png'},
{name: "Stephen Shaw", image: 'stephenshaw.png'},
{name: "XuXue Feng", image: 'xuxuefeng.png'}
]);
const statuses = ref([
'unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal'
]);
return { customers, customerService, selectedCustomer1, selectedCustomer2, filters1, filters2, loading, representatives, statuses }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-inputtext": primevue.inputtext,
"p-multiselect": primevue.multiselect,
"p-dropdown": primevue.dropdown
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
customerService: null,
created() {
this.customerService = new CustomerService();
this.initFilters1();
this.initFilters2();
},
mounted() {
this.customerService.getCustomersMedium().then((data) => (this.customers = data));
},
methods: {
initFilters1() {
this.filters1 = {
global: { value: null, matchMode: FilterMatchMode.CONTAINS }
};
},
initFilters2() {
this.filters2 = {
global: { value: null, matchMode: FilterMatchMode.CONTAINS }
};
}
}
};
</script>

View File

@ -0,0 +1,152 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Striped Rows</span></h1>
<p>Adding <i>stripedRows</i> displays rows with alternating colors.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" stripedRows responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableStripedDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableStripedDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" stripedRows responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" stripedRows responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="products" striped-rows responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
return { products }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
}
};
</script>

View File

@ -0,0 +1,319 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Style</span></h1>
<p>Certain rows or cells can easily be styled based on conditions.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" :rowClass="rowClass" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity">
<template #body="slotProps">
<div :class="stockClass(slotProps.data)">
{{ slotProps.data.quantity }}
</div>
</template>
</Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableStyleDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableStyleDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" :rowClass="rowClass" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity">
<template #body="slotProps">
<div :class="stockClass(slotProps.data)">
{{slotProps.data.quantity}}
</div>
</template>
</Column>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
rowClass(data) {
return data.category === 'Accessories' ? 'row-accessories': null;
},
stockClass(data) {
return [
{
'outofstock': data.quantity === 0,
'lowstock': data.quantity > 0 && data.quantity<10,
'instock': data.quantity > 10
}
];
}
}
}
<\\/script>
<style scoped lang="scss">
.outofstock {
font-weight: 700;
color: #FF5252;
text-decoration: line-through;
}
.lowstock {
font-weight: 700;
color: #FFA726;
}
.instock {
font-weight: 700;
color: #66BB6A;
}
::v-deep(.row-accessories) {
background-color: rgba(0,0,0,.15) !important;
}
</style>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" :rowClass="rowClass" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity">
<template #body="slotProps">
<div :class="stockClass(slotProps.data)">
{{slotProps.data.quantity}}
</div>
</template>
</Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
const rowClass = (data) => {
return data.category === 'Accessories' ? 'row-accessories': null;
};
const stockClass = (data) => {
return [
{
'outofstock': data.quantity === 0,
'lowstock': data.quantity > 0 && data.quantity<10,
'instock': data.quantity > 10
}
];
};
return { products, rowClass, stockClass }
}
}
<\\/script>
<style scoped lang="scss">
.outofstock {
font-weight: 700;
color: #FF5252;
text-decoration: line-through;
}
.lowstock {
font-weight: 700;
color: #FFA726;
}
.instock {
font-weight: 700;
color: #66BB6A;
}
::v-deep(.row-accessories) {
background-color: rgba(0,0,0,.15) !important;
}
</style>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="products" :row-class="rowClass" responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity">
<template #body="slotProps">
<div :class="stockClass(slotProps.data)">
{{slotProps.data.quantity}}
</div>
</template>
</p-column>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
const rowClass = (data) => {
return data.category === 'Accessories' ? 'row-accessories': null;
};
const stockClass = (data) => {
return [
{
'outofstock': data.quantity === 0,
'lowstock': data.quantity > 0 && data.quantity<10,
'instock': data.quantity > 10
}
];
};
return { products, rowClass, stockClass }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.outofstock {
font-weight: 700;
color: #FF5252;
text-decoration: line-through;
}
.lowstock {
font-weight: 700;
color: #FFA726;
}
.instock {
font-weight: 700;
color: #66BB6A;
}
.row-accessories {
background-color: rgba(0,0,0,.15) !important;
}
</style>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
rowClass(data) {
return data.category === 'Accessories' ? 'row-accessories' : null;
},
stockClass(data) {
return [
{
outofstock: data.quantity === 0,
lowstock: data.quantity > 0 && data.quantity < 10,
instock: data.quantity > 10
}
];
}
}
};
</script>
<style scoped lang="scss">
.outofstock {
font-weight: 700;
color: #ff5252;
text-decoration: line-through;
}
.lowstock {
font-weight: 700;
color: #ffa726;
}
.instock {
font-weight: 700;
color: #66bb6a;
}
::v-deep(.row-accessories) {
background-color: rgba(0, 0, 0, 0.15) !important;
}
</style>

View File

@ -0,0 +1,327 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>Templating</span></h1>
<p>Custom content at header, body and footer sections are supported via templating.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
<div class="table-header">
Products
<Button icon="pi pi-refresh" />
</div>
</template>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.image" class="product-image" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{ slotProps.data.inventoryStatus }}</span>
</template>
</Column>
<template #footer> In total there are {{ products ? products.length : 0 }} products. </template>
</DataTable>
</div>
</div>
<AppDoc name="DataTableTemplatingDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="datatable/DataTableTemplatingDemo.vue" />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
export default {
data() {
return {
products: null,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
<div class="table-header">
Products
<Button icon="pi pi-refresh" />
</div>
</template>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.image" class="product-image" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<template #footer>
In total there are {{products ? products.length : 0 }} products.
</template>
</DataTable>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data);
},
methods: {
formatCurrency(value) {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
}
}
}
<\\/script>
<style lang="scss" scoped>
.table-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.product-image {
width: 50px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
</style>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<DataTable :value="products" responsiveLayout="scroll">
<template #header>
<div class="table-header">
Products
<Button icon="pi pi-refresh" />
</div>
</template>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.image" class="product-image" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
</template>
</Column>
<template #footer>
In total there are {{products ? products.length : 0 }} products.
</template>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductService from './service/ProductService';
export default {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { products, formatCurrency }
}
}
<\\/script>
<style lang="scss" scoped>
.table-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.product-image {
width: 50px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
</style>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/rating/rating.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-datatable :value="products" responsive-layout="scroll">
<template #header>
<div class="table-header">
Products
<p-button icon="pi pi-refresh"></p-button>
</div>
</template>
<p-column field="name" header="Name"></p-column>
<p-column header="Image">
<template #body="slotProps">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" :alt="slotProps.data.image" class="product-image" />
</template>
</p-column>
<p-column field="price" header="Price">
<template #body="slotProps">
{{formatCurrency(slotProps.data.price)}}
</template>
</p-column>
<p-column field="rating" header="Reviews">
<template #body="slotProps">
<p-rating :model-value="slotProps.data.rating" :readonly="true" :cancel="false"></p-rating>
</template>
</p-column>
<p-column header="Status">
<template #body="slotProps">
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{slotProps.data.inventoryStatus}}</span>
</template>
</p-column>
<template #footer>
In total there are {{products ? products.length : 0 }} products.
</template>
</p-datatable>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
productService.value.getProductsSmall().then(data => products.value = data);
})
const products = ref();
const productService = ref(new ProductService());
const formatCurrency = (value) => {
return value.toLocaleString('en-US', {style: 'currency', currency: 'USD'});
};
return { products, formatCurrency }
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-button": primevue.button,
"p-rating": primevue.rating
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.table-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.product-image {
width: 50px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23)
}
</style>
`
}
}
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data));
},
methods: {
formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
}
};
</script>
<style lang="scss" scoped>
.table-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.product-image {
width: 100px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
</style>

View File

@ -0,0 +1,435 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataTable <span>VirtualScroll</span></h1>
<p>VirtualScroller is a performant approach to handle huge data efficiently.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Preloaded Data (100000 Rows)</h5>
<DataTable :value="cars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ itemSize: 46 }">
<Column field="id" header="Id" style="min-width: '200px'"></Column>
<Column field="vin" header="Vin" style="min-width: '200px'"></Column>
<Column field="year" header="Year" style="min-width: '200px'"></Column>
<Column field="brand" header="Brand" style="min-width: '200px'"></Column>
<Column field="color" header="Color" style="min-width: '200px'"></Column>
</DataTable>
</div>
<div class="card">
<h5>Lazy Loading from a Remote Datasource (100000 Rows)</h5>
<DataTable :value="virtualCars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }">
<Column field="id" header="Id" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
<Column field="vin" header="Vin" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="year" header="Year" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="30%" height="1rem" />
</div>
</template>
</Column>
<Column field="brand" header="Brand" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="color" header="Color" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{ height: '17px', 'flex-grow': '1', overflow: 'hidden' }">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
</DataTable>
</div>
</div>
<AppDoc name="DataTableVirtualScrollDemo" :sources="sources" :service="['CarService']" github="datatable/DataTableVirtualScrollDemo.vue" />
</div>
</template>
<script>
import CarService from '../../service/CarService';
export default {
data() {
return {
cars: null,
virtualCars: Array.from({ length: 100000 }),
lazyLoading: false,
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Preloaded Data (100000 Rows)</h5>
<DataTable :value="cars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ itemSize: 46 }">
<Column field="id" header="Id" style="min-width: '200px'"></Column>
<Column field="vin" header="Vin" style="min-width: '200px'"></Column>
<Column field="year" header="Year" style="min-width: '200px'"></Column>
<Column field="brand" header="Brand" style="min-width: '200px'"></Column>
<Column field="color" header="Color" style="min-width: '200px'"></Column>
</DataTable>
</div>
<div class="card">
<h5>Lazy Loading from a Remote Datasource (100000 Rows)</h5>
<DataTable :value="virtualCars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }">
<Column field="id" header="Id" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
<Column field="vin" header="Vin" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="year" header="Year" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="30%" height="1rem" />
</div>
</template>
</Column>
<Column field="brand" header="Brand" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="color" header="Color" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import CarService from './service/CarService';
export default {
data() {
return {
cars: null,
virtualCars: Array.from({ length: 100000 }),
lazyLoading: false
}
},
carService: null,
loadLazyTimeout: null,
created() {
this.carService = new CarService();
},
mounted() {
this.cars = Array.from({ length: 100000 }).map((_, i) => this.carService.generateCar(i + 1));
},
methods: {
loadCarsLazy(event) {
!this.lazyLoading && (this.lazyLoading = true);
if (this.loadLazyTimeout) {
clearTimeout(this.loadLazyTimeout);
}
//simulate remote connection with a timeout
this.loadLazyTimeout = setTimeout(() => {
let virtualCars = [...this.virtualCars];
let { first, last } = event;
//load data of required page
const loadedCars = this.cars.slice(first, last);
//populate page of virtual cars
Array.prototype.splice.apply(virtualCars, [...[first, last - first], ...loadedCars]);
this.virtualCars = virtualCars;
this.lazyLoading = false;
}, Math.random() * 1000 + 250);
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Preloaded Data (100000 Rows)</h5>
<DataTable :value="cars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ itemSize: 46 }">
<Column field="id" header="Id" style="min-width: '200px'"></Column>
<Column field="vin" header="Vin" style="min-width: '200px'"></Column>
<Column field="year" header="Year" style="min-width: '200px'"></Column>
<Column field="brand" header="Brand" style="min-width: '200px'"></Column>
<Column field="color" header="Color" style="min-width: '200px'"></Column>
</DataTable>
</div>
<div class="card">
<h5>Lazy Loading from a Remote Datasource (100000 Rows)</h5>
<DataTable :value="virtualCars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }">
<Column field="id" header="Id" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
<Column field="vin" header="Vin" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="year" header="Year" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="30%" height="1rem" />
</div>
</template>
</Column>
<Column field="brand" header="Brand" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="40%" height="1rem" />
</div>
</template>
</Column>
<Column field="color" header="Color" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<Skeleton width="60%" height="1rem" />
</div>
</template>
</Column>
</DataTable>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { FilterMatchMode } from 'primevue/api';
import CustomerService from './service/CustomerService';
export default {
setup() {
onMounted(() => {
cars.value = Array.from({ length: 100000 }).map((_, i) => carService.value.generateCar(i + 1));
})
const cars = ref(null);
const virtualCars = ref(Array.from({ length: 100000 }));
const lazyLoading = ref(false);
const carService = ref(new CarService());
const loadLazyTimeout = ref();
const loadCarsLazy = (event) => {
!lazyLoading.value && (lazyLoading.value = true);
if (loadLazyTimeout.value) {
clearTimeout(loadLazyTimeout.value);
}
//simulate remote connection with a timeout
loadLazyTimeout.value = setTimeout(() => {
let _virtualCars = [...virtualCars.value];
let { first, last } = event;
//load data of required page
const loadedCars = cars.value.slice(first, last);
//populate page of virtual cars
Array.prototype.splice.apply(_virtualCars, [...[first, last - first], ...loadedCars]);
virtualCars.value = _virtualCars;
lazyLoading.value = false;
}, Math.random() * 1000 + 250);
}
return { cars, virtualCars, lazyLoading, loadCarsLazy };
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/skeleton/skeleton.min.js"><\\/script>
<script src="./CarService.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<h5>Preloaded Data (100000 Rows)</h5>
<p-datatable :value="cars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ itemSize: 46 }">
<p-column field="id" header="Id" style="min-width: '200px'"></p-column>
<p-column field="vin" header="Vin" style="min-width: '200px'"></p-column>
<p-column field="year" header="Year" style="min-width: '200px'"></p-column>
<p-column field="brand" header="Brand" style="min-width: '200px'"></p-column>
<p-column field="color" header="Color" style="min-width: '200px'"></p-column>
</p-datatable>
</div>
<div class="card">
<h5>Lazy Loading from a Remote Datasource (100000 Rows)</h5>
<p-datatable :value="virtualCars" scrollable scrollHeight="400px" :virtualScrollerOptions="{ lazy: true, onLazyLoad: loadCarsLazy, itemSize: 46, delay: 200, showLoader: true, loading: lazyLoading, numToleratedItems: 10 }">
<p-column field="id" header="Id" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<p-skeleton width="60%" height="1rem" />
</div>
</template>
</p-column>
<p-column field="vin" header="Vin" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<p-skeleton width="40%" height="1rem" />
</div>
</template>
</p-column>
<p-column field="year" header="Year" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<p-skeleton width="30%" height="1rem" />
</div>
</template>
</p-column>
<p-column field="brand" header="Brand" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<p-skeleton width="40%" height="1rem" />
</div>
</template>
</p-column>
<p-column field="color" header="Color" style="min-width: '200px'">
<template #loading>
<div class="flex align-items-center" :style="{height: '17px', 'flex-grow': '1', overflow: 'hidden'}">
<p-skeleton width="60%" height="1rem" />
</div>
</template>
</p-column>
</p-datatable>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
onMounted(() => {
cars.value = Array.from({ length: 100000 }).map((_, i) => carService.value.generateCar(i + 1));
})
const cars = ref(null);
const virtualCars = ref(Array.from({ length: 100000 }));
const lazyLoading = ref(false);
const carService = ref(new CarService());
const loadLazyTimeout = ref();
const loadCarsLazy = (event) => {
!lazyLoading.value && (lazyLoading.value = true);
if (loadLazyTimeout.value) {
clearTimeout(loadLazyTimeout.value);
}
//simulate remote connection with a timeout
loadLazyTimeout.value = setTimeout(() => {
let _virtualCars = [...virtualCars.value];
let { first, last } = event;
//load data of required page
const loadedCars = cars.value.slice(first, last);
//populate page of virtual cars
Array.prototype.splice.apply(_virtualCars, [...[first, last - first], ...loadedCars]);
virtualCars.value = _virtualCars;
lazyLoading.value = false;
}, Math.random() * 1000 + 250);
}
return { cars, virtualCars, lazyLoading, loadCarsLazy };
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-skeleton": primevue.skeleton
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
},
carService: null,
loadLazyTimeout: null,
created() {
this.carService = new CarService();
},
mounted() {
this.cars = Array.from({ length: 100000 }).map((_, i) => this.carService.generateCar(i + 1));
},
methods: {
loadCarsLazy(event) {
!this.lazyLoading && (this.lazyLoading = true);
if (this.loadLazyTimeout) {
clearTimeout(this.loadLazyTimeout);
}
//simulate remote connection with a timeout
this.loadLazyTimeout = setTimeout(() => {
let virtualCars = [...this.virtualCars];
let { first, last } = event;
//load data of required page
const loadedCars = this.cars.slice(first, last);
//populate page of virtual cars
Array.prototype.splice.apply(virtualCars, [...[first, last - first], ...loadedCars]);
this.virtualCars = virtualCars;
this.lazyLoading = false;
}, Math.random() * 1000 + 250);
}
}
};
</script>

1201
pages/dataview/DataViewDoc.vue Executable file

File diff suppressed because it is too large Load Diff

243
pages/dataview/index.vue Executable file
View File

@ -0,0 +1,243 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DataView</h1>
<p>DataView displays data in grid or list layout with pagination and sorting features.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<DataView :value="products" :layout="layout" :paginator="true" :rows="9" :sortOrder="sortOrder" :sortField="sortField">
<template #header>
<div class="grid grid-nogutter">
<div class="col-6" style="text-align: left">
<Dropdown v-model="sortKey" :options="sortOptions" optionLabel="label" placeholder="Sort By Price" @change="onSortChange($event)" />
</div>
<div class="col-6" style="text-align: right">
<DataViewLayoutOptions v-model="layout" />
</div>
</div>
</template>
<template #list="slotProps">
<div class="col-12">
<div class="product-list-item">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.name" />
<div class="product-list-detail">
<div class="product-name">{{ slotProps.data.name }}</div>
<div class="product-description">{{ slotProps.data.description }}</div>
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false"></Rating>
<i class="pi pi-tag product-category-icon"></i><span class="product-category">{{ slotProps.data.category }}</span>
</div>
<div class="product-list-action">
<span class="product-price">${{ slotProps.data.price }}</span>
<Button icon="pi pi-shopping-cart" label="Add to Cart" :disabled="slotProps.data.inventoryStatus === 'OUTOFSTOCK'"></Button>
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{ slotProps.data.inventoryStatus }}</span>
</div>
</div>
</div>
</template>
<template #grid="slotProps">
<div class="col-12 md:col-4">
<div class="product-grid-item card">
<div class="product-grid-item-top">
<div>
<i class="pi pi-tag product-category-icon"></i>
<span class="product-category">{{ slotProps.data.category }}</span>
</div>
<span :class="'product-badge status-' + slotProps.data.inventoryStatus.toLowerCase()">{{ slotProps.data.inventoryStatus }}</span>
</div>
<div class="product-grid-item-content">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.name" />
<div class="product-name">{{ slotProps.data.name }}</div>
<div class="product-description">{{ slotProps.data.description }}</div>
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false"></Rating>
</div>
<div class="product-grid-item-bottom">
<span class="product-price">${{ slotProps.data.price }}</span>
<Button icon="pi pi-shopping-cart" :disabled="slotProps.data.inventoryStatus === 'OUTOFSTOCK'"></Button>
</div>
</div>
</div>
</template>
</DataView>
</div>
</div>
<DataViewDoc />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
import DataViewDoc from './DataViewDoc';
export default {
data() {
return {
products: null,
layout: 'grid',
sortKey: null,
sortOrder: null,
sortField: null,
sortOptions: [
{ label: 'Price High to Low', value: '!price' },
{ label: 'Price Low to High', value: 'price' }
]
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProducts().then((data) => (this.products = data));
},
methods: {
onSortChange(event) {
const value = event.value.value;
const sortValue = event.value;
if (value.indexOf('!') === 0) {
this.sortOrder = -1;
this.sortField = value.substring(1, value.length);
this.sortKey = sortValue;
} else {
this.sortOrder = 1;
this.sortField = value;
this.sortKey = sortValue;
}
}
},
components: {
DataViewDoc: DataViewDoc
}
};
</script>
<style lang="scss" scoped>
.p-dropdown {
width: 14rem;
font-weight: normal;
}
.product-name {
font-size: 1.5rem;
font-weight: 700;
}
.product-description {
margin: 0 0 1rem 0;
}
.product-category-icon {
vertical-align: middle;
margin-right: 0.5rem;
}
.product-category {
font-weight: 600;
vertical-align: middle;
}
::v-deep(.product-list-item) {
display: flex;
align-items: center;
padding: 1rem;
width: 100%;
img {
width: 150px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
margin-right: 2rem;
}
.product-list-detail {
flex: 1 1 0;
}
.p-rating {
margin: 0 0 0.5rem 0;
}
.product-price {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 0.5rem;
align-self: flex-end;
}
.product-list-action {
display: flex;
flex-direction: column;
}
.p-button {
margin-bottom: 0.5rem;
}
}
::v-deep(.product-grid-item) {
margin: 0.5rem;
border: 1px solid var(--surface-border);
.product-grid-item-top,
.product-grid-item-bottom {
display: flex;
align-items: center;
justify-content: space-between;
}
img {
width: 75%;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
margin: 2rem 0;
}
.product-grid-item-content {
text-align: center;
}
.product-price {
font-size: 1.5rem;
font-weight: 600;
}
}
@media screen and (max-width: 576px) {
.product-list-item {
flex-direction: column;
align-items: center;
img {
width: 75%;
margin: 2rem 0;
}
.product-list-detail {
text-align: center;
}
.product-price {
align-self: center;
}
.product-list-action {
display: flex;
flex-direction: column;
}
.product-list-action {
margin-top: 2rem;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
}
}
}
</style>

View File

@ -0,0 +1,279 @@
<template>
<AppDoc name="DeferredContentDemo" :sources="sources" :service="['ProductService']" :data="['products-small']" github="deferredcontent/DeferredContentDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import DeferredContent from 'primevue/deferredcontent';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/deferredcontent/deferredcontent.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>DeferredContent is used as a wrapper element of its content..</p>
<pre v-code><code><template v-pre>
&lt;DeferredContent&gt;
&lt;DataTable :value="cars"&gt;
&lt;Column field="vin" header="Vin"&gt;&lt;/Column&gt;
&lt;Column field="year" header="Year"&gt;&lt;/Column&gt;
&lt;Column field="brand" header="Brand"&gt;&lt;/Column&gt;
&lt;Column field="color" header="Color"&gt;&lt;/Column&gt;
&lt;/DataTable&gt;
&lt;/DeferredContent&gt;
</template>
</code></pre>
<h5>Load Event</h5>
<p>onLoad callback is useful to initialize the content when it becomes visible on scroll such as loading data.</p>
<pre v-code><code><template v-pre>
&lt;DeferredContent @load="onDataLoad"&gt;
&lt;DataTable :value="cars"&gt;
&lt;Column field="vin" header="Vin"&gt;&lt;/Column&gt;
&lt;Column field="year" header="Year"&gt;&lt;/Column&gt;
&lt;Column field="brand" header="Brand"&gt;&lt;/Column&gt;
&lt;Column field="color" header="Color"&gt;&lt;/Column&gt;
&lt;/DataTable&gt;
&lt;/DeferredContent&gt;
</template>
</code></pre>
<h5>Properties</h5>
<p>Component has no properties.</p>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>load</td>
<td>event: Event object</td>
<td>Callback to invoke when deferred content is loaded..</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Component does not apply any styling.</p>
<h5>Accessibility</h5>
<DevelopmentSection>
<h6>Screen Reader</h6>
<p>
DeferredContent can be utilized in many use cases as a result no role is enforced, in fact a role may not be necessary if the card is used for presentational purposes only. Any valid attribute is passed to the container element so you
have full control over the roles like <a href="https://www.w3.org/TR/wai-aria/#landmark" alt="Landmark Roles">landmark</a> and attributes like <i>aria-live</i>.
</p>
<pre v-code><code>
&lt;DeferredContent role="region" aria-live="polite" aria-label="Content loaded after page scrolled down"&gt;
Content
&lt;/DeferredContent&gt;
</code></pre>
<h5>Keyboard Support</h5>
<p>Component does not include any interactive elements.</p>
</DevelopmentSection>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Toast />
<div style="height: 800px">
Scroll down to lazy load an image and the DataTable which initiates a query that is not executed on initial page load to speed up load performance.
</div>
<DeferredContent @load="onImageLoad">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" alt="Nature"/>
</DeferredContent>
<div style="height: 500px">
</div>
<DeferredContent @load="onDataLoad">
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</DeferredContent>
</div>
</template>
<script>
import ProductService from './service/ProductService';
export default {
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
methods: {
onImageLoad() {
this.$toast.add({severity: 'success', summary: 'Image Initialized', detail: 'Scroll down to load the datatable'});
},
onDataLoad() {
this.productService.getProductsSmall().then(data => this.products = data);
this.$toast.add({severity: 'success', summary: 'Data Initialized', detail: 'Render Completed'});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Toast />
<div style="height: 800px">
Scroll down to lazy load an image and the DataTable which initiates a query that is not executed on initial page load to speed up load performance.
</div>
<DeferredContent @load="onImageLoad">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" alt="Nature"/>
</DeferredContent>
<div style="height: 500px">
</div>
<DeferredContent @load="onDataLoad">
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</DeferredContent>
</div>
</template>
<script>
import { ref } from 'vue';
import { useToast } from "primevue/usetoast";
import ProductService from './service/ProductService';
export default {
setup() {
const toast = useToast();
const products = ref();
const productService = ref(new ProductService());
const onImageLoad = () => {
toast.add({severity: 'success', summary: 'Image Initialized', detail: 'Scroll down to load the datatable'});
};
const onDataLoad = () => {
productService.value.getProductsSmall().then(data => products.value = data);
toast.add({severity: 'success', summary: 'Data Initialized', detail: 'Render Completed'});
};
return { products, productService, onImageLoad, onDataLoad }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/deferredcontent/deferredcontent.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-toast></p-toast>
<div style="height: 800px">
Scroll down to lazy load an image and the DataTable which initiates a query that is not executed on initial page load to speed up load performance.
</div>
<p-deferredcontent @load="onImageLoad">
<img src="https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png" alt="Nature"/>
</p-deferredcontent>
<div style="height: 500px">
</div>
<p-deferredcontent @load="onDataLoad">
<p-datatable :value="products" responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
</p-datatable>
</p-deferredcontent>
</div>
<script type="module">
const { createApp, ref } = Vue;
const { useToast } = primevue.usetoast;
const App = {
setup() {
const toast = useToast();
const products = ref();
const productService = ref(new ProductService());
const onImageLoad = () => {
toast.add({severity: 'success', summary: 'Image Initialized', detail: 'Scroll down to load the datatable'});
};
const onDataLoad = () => {
productService.value.getProductsSmall().then(data => products.value = data);
toast.add({severity: 'success', summary: 'Data Initialized', detail: 'Render Completed'});
};
return { products, productService, onImageLoad, onDataLoad }
},
components: {
"p-deferredcontent": primevue.deferredcontent,
"p-toast": primevue.toast,
"p-datatable": primevue.datatable,
"p-column": primevue.column
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

63
pages/deferredcontent/index.vue Executable file
View File

@ -0,0 +1,63 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>DeferredContent</h1>
<p>DeferredContent postpones the loading the content that is initially not in the viewport until it becomes visible on scroll.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<div style="height: 800px">Scroll down to lazy load an image and the DataTable which initiates a query that is not executed on initial page load to speed up load performance.</div>
<!-- <DeferredContent @load="onImageLoad">
<img src="demo/images/nature/nature4.jpg" alt="Nature"/>
</DeferredContent> -->
<div style="height: 500px"></div>
<DeferredContent @load="onDataLoad" role="region" aria-live="polite" aria-label="Content loaded after page scrolled down">
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
</DataTable>
</DeferredContent>
</div>
</div>
<DeferredContentDoc />
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
import DeferredContentDoc from './DeferredContentDoc';
export default {
data() {
return {
products: null
};
},
productService: null,
created() {
this.productService = new ProductService();
},
methods: {
onImageLoad() {
this.$toast.add({ severity: 'success', summary: 'Image Initialized', detail: 'Scroll down to load the datatable' });
},
onDataLoad() {
this.productService.getProductsSmall().then((data) => (this.products = data));
this.$toast.add({ severity: 'success', summary: 'Data Initialized', detail: 'Render Completed' });
}
},
components: {
DeferredContentDoc: DeferredContentDoc
}
};
</script>

985
pages/dialog/DialogDoc.vue Executable file
View File

@ -0,0 +1,985 @@
<template>
<AppDoc name="DialogDemo" :sources="sources" github="dialog/DialogDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Dialog from 'primevue/dialog';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Dialog is used as a container and visibility is managed with <i>visible</i> property that requires the v-model for two-way binding.</p>
<pre v-code><code>
&lt;Dialog header="Header" v-model:visible="display" &gt;
Content
&lt;/Dialog&gt;
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
display: false
}
}
}
</code></pre>
<h5>Header and Footer</h5>
<p>Header and Footer sections are defined using properties with the same name that accept simple strings or with the <i>header</i> and <i>footer</i> templates for custom content.</p>
<pre v-code><code>
&lt;Dialog header="Header" footer="Footer" v-model:visible="display"&gt;
Content
&lt;/Dialog&gt;
</code></pre>
<pre v-code><code>
&lt;Dialog v-model:visible="display"&gt;
&lt;template #header&gt;
&lt;h3&gt;Header&lt;/h3&gt;
&lt;/template&gt;
Content
&lt;template #footer&gt;
&lt;Button label="No" icon="pi pi-times" class="p-button-text"/&gt;
&lt;Button label="Yes" icon="pi pi-check" autofocus /&gt;
&lt;/template&gt;
&lt;/Dialog&gt;
</code></pre>
<h5>Positioning</h5>
<p>Dialog location is controlled with the <i>position</i> property whose default value is center. Other valid values are top", "bottom", "left", "right", "topleft", "topright", "bottomleft" and "bottomright".</p>
<pre v-code><code>
&lt;Dialog position="top" v-model:visible="display"&gt;
Content
&lt;/Dialog&gt;
</code></pre>
<h5>Responsive</h5>
<p>
Dialog width can be adjusted per screen size with the <i>breakpoints</i> option. In example below, default width is set to 50vw and below 961px, width would be 75vw and finally below 641px width becomes 100%. The value of
<i>breakpoints</i> should be an object literal whose keys are the maximum screen sizes and values are the widths per screen.
</p>
<pre v-code><code>
&lt;Dialog v-model:visible="display" :breakpoints="{'960px': '75vw', '640px': '100vw'}" :style="{width: '50vw'}"&gt;
Content
&lt;/Dialog&gt;
</code></pre>
<h5>Initial Focus</h5>
<p>Adding <i>autofocus</i> to an element in the dialog makes it the initial focus target when dialog gets shown.</p>
<pre v-code><code>
&lt;Dialog v-model:visible="display"&gt;
Content
&lt;template #footer&gt;
&lt;Button label="No" /&gt;
&lt;Button label="Yes" autofocus/&gt;
&lt;/template&gt;
&lt;/Dialog&gt;
</code></pre>
<h5>Properties</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>header</td>
<td>any</td>
<td>null</td>
<td>Title content of the dialog.</td>
</tr>
<tr>
<td>footer</td>
<td>any</td>
<td>null</td>
<td>Footer content of the dialog.</td>
</tr>
<tr>
<td>visible</td>
<td>boolean</td>
<td>false</td>
<td>Specifies the visibility of the dialog.</td>
</tr>
<tr>
<td>modal</td>
<td>boolean</td>
<td>null</td>
<td>Defines if background should be blocked when dialog is displayed.</td>
</tr>
<tr>
<td>closeOnEscape</td>
<td>boolean</td>
<td>true</td>
<td>Specifies if pressing escape key should hide the dialog.</td>
</tr>
<tr>
<td>dismissableMask</td>
<td>boolean</td>
<td>false</td>
<td>Specifies if clicking the modal background should hide the dialog.</td>
</tr>
<tr>
<td>position</td>
<td>string</td>
<td>center</td>
<td>Position of the dialog, options are "center", "top", "bottom", "left", "right", "topleft", "topright", "bottomleft" or "bottomright".</td>
</tr>
<tr>
<td>contentStyle</td>
<td>object</td>
<td>null</td>
<td>Style of the content section.</td>
</tr>
<tr>
<td>contentClass</td>
<td>string</td>
<td>null</td>
<td>Style class of the content section.</td>
</tr>
<tr>
<td>rtl</td>
<td>boolean</td>
<td>null</td>
<td>When enabled dialog is displayed in RTL direction.</td>
</tr>
<tr>
<td>closable</td>
<td>boolean</td>
<td>true</td>
<td>Adds a close icon to the header to hide the dialog.</td>
</tr>
<tr>
<td>showHeader</td>
<td>boolean</td>
<td>true</td>
<td>Whether to show the header or not.</td>
</tr>
<tr>
<td>baseZIndex</td>
<td>number</td>
<td>0</td>
<td>Base zIndex value to use in layering.</td>
</tr>
<tr>
<td>autoZIndex</td>
<td>boolean</td>
<td>true</td>
<td>Whether to automatically manage layering.</td>
</tr>
<tr>
<td>ariaCloseLabel</td>
<td>string</td>
<td>close</td>
<td>Aria label of the close icon.</td>
</tr>
<tr>
<td>maximizable</td>
<td>boolean</td>
<td>false</td>
<td>Whether the dialog can be displayed full screen.</td>
</tr>
<tr>
<td>breakpoints</td>
<td>object</td>
<td>null</td>
<td>Object literal to define widths per screen size.</td>
</tr>
<tr>
<td>draggable</td>
<td>boolean</td>
<td>true</td>
<td>Enables dragging to change the position using header.</td>
</tr>
<tr>
<td>minX</td>
<td>number</td>
<td>0</td>
<td>Minimum value for the left coordinate of dialog in dragging.</td>
</tr>
<tr>
<td>minY</td>
<td>number</td>
<td>0</td>
<td>Minimum value for the top coordinate of dialog in dragging.</td>
</tr>
<tr>
<td>keepInViewport</td>
<td>boolean</td>
<td>true</td>
<td>Keeps dialog in the viewport when dragging.</td>
</tr>
<tr>
<td>appendTo</td>
<td>string</td>
<td>body</td>
<td>A valid query selector or an HTMLElement to specify where the dialog gets attached. Special keywords are "body" for document body and "self" for the element itself.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>hide</td>
<td>-</td>
<td>Callback to invoke when dialog is hidden.</td>
</tr>
<tr>
<td>after-hide</td>
<td>-</td>
<td>Callback to invoke after dialog is hidden.</td>
</tr>
<tr>
<td>show</td>
<td>-</td>
<td>Callback to invoke when dialog is showed.</td>
</tr>
<tr>
<td>maximize</td>
<td>event: Event object</td>
<td>Fired when a dialog gets maximized.</td>
</tr>
<tr>
<td>unmaximize</td>
<td>event: Event object</td>
<td>Fired when a dialog gets unmaximized.</td>
</tr>
<tr>
<td>dragend</td>
<td>event: Event object</td>
<td>Fired when a dialog drag completes..</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>header</td>
<td>-</td>
</tr>
<tr>
<td>footer</td>
<td>-</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-dialog</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-dialog-titlebar</td>
<td>Container of header.</td>
</tr>
<tr>
<td>p-dialog-title</td>
<td>Header element.</td>
</tr>
<tr>
<td>p-dialog-titlebar-icon</td>
<td>Icon container inside header.</td>
</tr>
<tr>
<td>p-dialog-titlebar-close</td>
<td>Close icon element.</td>
</tr>
<tr>
<td>p-dialog-content</td>
<td>Content element</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<Button label="Show" icon="pi pi-external-link" @click="openBasic" />
<Dialog header="Header" v-model:visible="displayBasic" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeBasic" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeBasic" autofocus />
</template>
</Dialog>
<Button label="Long Content" icon="pi pi-external-link" @click="openBasic2" />
<Dialog header="Header" v-model:visible="displayBasic2" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.</p>
<p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,
quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur,
vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident,
similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio
cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe
eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeBasic2" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeBasic2" autofocus />
</template>
</Dialog>
<h5>Modal</h5>
<Button label="Show" icon="pi pi-external-link" @click="openModal" />
<Dialog header="Header" v-model:visible="displayModal" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeModal" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeModal" autofocus />
</template>
</Dialog>
<h5>Responsive</h5>
<Button label="Show" icon="pi pi-external-link" @click="openResponsive" />
<Dialog header="Header" v-model:visible="displayResponsive" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeResponsive" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeResponsive" autofocus />
</template>
</Dialog>
<h5>Confirmation</h5>
<Button label="Confirm" icon="pi pi-external-link" @click="openConfirmation" />
<Dialog header="Confirmation" v-model:visible="displayConfirmation" :style="{width: '350px'}" :modal="true">
<div class="confirmation-content">
<i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem" />
<span>Are you sure you want to proceed?</span>
</div>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeConfirmation" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeConfirmation" class="p-button-text" autofocus />
</template>
</Dialog>
<h5>Maximizable</h5>
<Button label="Show" icon="pi pi-external-link" @click="openMaximizable" />
<Dialog header="Header" v-model:visible="displayMaximizable" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :maximizable="true" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeMaximizable" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeMaximizable" autofocus />
</template>
</Dialog>
<h5>Position</h5>
<div class="grid flex-column">
<div class="col">
<Button label="Left" icon="pi pi-arrow-right" @click="openPosition('left')" class="p-button-warning" />
<Button label="Right" icon="pi pi-arrow-left" @click="openPosition('right')" class="p-button-warning" />
</div>
<div class="col">
<Button label="Top" icon="pi pi-arrow-down" @click="openPosition('top')" class="p-button-warning" />
<Button label="TopLeft" icon="pi pi-arrow-down-right" @click="openPosition('topleft')" class="p-button-warning" />
<Button label="TopRight" icon="pi pi-arrow-down-left" @click="openPosition('topright')" class="p-button-warning" />
</div>
<div class="col">
<Button label="Bottom" icon="pi pi-arrow-up" @click="openPosition('bottom')" class="p-button-warning" />
<Button label="BottomLeft" icon="pi pi-arrow-up-right" @click="openPosition('bottomleft')" class="p-button-warning" />
<Button label="BottomRight" icon="pi pi-arrow-up-left" @click="openPosition('bottomright')" class="p-button-warning" />
</div>
</div>
<Dialog header="Header" v-model:visible="displayPosition" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :position="position" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closePosition" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closePosition" autofocus />
</template>
</Dialog>
</div>
</template>
<script>
export default {
data() {
return {
displayBasic: false,
displayBasic2: false,
displayModal: false,
displayResponsive: false,
displayConfirmation: false,
displayMaximizable: false,
displayPosition: false,
position: 'center'
}
},
methods: {
openBasic() {
this.displayBasic = true;
},
closeBasic() {
this.displayBasic = false;
},
openBasic2() {
this.displayBasic2 = true;
},
closeBasic2() {
this.displayBasic2 = false;
},
openResponsive() {
this.displayResponsive = true;
},
closeResponsive() {
this.displayResponsive = false;
},
openModal() {
this.displayModal = true;
},
closeModal() {
this.displayModal = false;
},
openConfirmation() {
this.displayConfirmation = true;
},
closeConfirmation() {
this.displayConfirmation = false;
},
openMaximizable() {
this.displayMaximizable = true;
},
closeMaximizable() {
this.displayMaximizable = false;
},
openPosition(position) {
this.position = position;
this.displayPosition = true;
},
closePosition() {
this.displayPosition = false;
}
}
}
<\\/script>
<style scoped lang="scss">
.p-button {
margin: 0.3rem .5rem;
min-width: 10rem;
}
p {
margin: 0;
}
.confirmation-content {
display: flex;
align-items: center;
justify-content: center;
}
.p-dialog .p-button {
min-width: 6rem;
}
</style>`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<h5>Basic</h5>
<Button label="Show" icon="pi pi-external-link" @click="openBasic" />
<Dialog header="Header" v-model:visible="displayBasic" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeBasic" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeBasic" autofocus />
</template>
</Dialog>
<Button label="Long Content" icon="pi pi-external-link" @click="openBasic2" />
<Dialog header="Header" v-model:visible="displayBasic2" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.</p>
<p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,
quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur,
vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident,
similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio
cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe
eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeBasic2" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeBasic2" autofocus />
</template>
</Dialog>
<h5>Modal</h5>
<Button label="Show" icon="pi pi-external-link" @click="openModal" />
<Dialog header="Header" v-model:visible="displayModal" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeModal" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeModal" autofocus />
</template>
</Dialog>
<h5>Responsive</h5>
<Button label="Show" icon="pi pi-external-link" @click="openResponsive" />
<Dialog header="Header" v-model:visible="displayResponsive" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeResponsive" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeResponsive" autofocus />
</template>
</Dialog>
<h5>Confirmation</h5>
<Button label="Confirm" icon="pi pi-external-link" @click="openConfirmation" />
<Dialog header="Confirmation" v-model:visible="displayConfirmation" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '350px'}" :modal="true">
<div class="confirmation-content">
<i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem" />
<span>Are you sure you want to proceed?</span>
</div>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeConfirmation" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeConfirmation" class="p-button-text" autofocus />
</template>
</Dialog>
<h5>Maximizable</h5>
<Button label="Show" icon="pi pi-external-link" @click="openMaximizable" />
<Dialog header="Header" v-model:visible="displayMaximizable" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :maximizable="true" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeMaximizable" class="p-button-text"/>
<Button label="Yes" icon="pi pi-check" @click="closeMaximizable" autofocus />
</template>
</Dialog>
<h5>Position</h5>
<div class="grid p-dir-col">
<div class="col">
<Button label="Left" icon="pi pi-arrow-right" @click="openPosition('left')" class="p-button-warning" />
<Button label="Right" icon="pi pi-arrow-left" @click="openPosition('right')" class="p-button-warning" />
</div>
<div class="col">
<Button label="Top" icon="pi pi-arrow-down" @click="openPosition('top')" class="p-button-warning" />
<Button label="TopLeft" icon="pi pi-arrow-down-right" @click="openPosition('topleft')" class="p-button-warning" />
<Button label="TopRight" icon="pi pi-arrow-down-left" @click="openPosition('topright')" class="p-button-warning" />
</div>
<div class="col">
<Button label="Bottom" icon="pi pi-arrow-up" @click="openPosition('bottom')" class="p-button-warning" />
<Button label="BottomLeft" icon="pi pi-arrow-up-right" @click="openPosition('bottomleft')" class="p-button-warning" />
<Button label="BottomRight" icon="pi pi-arrow-up-left" @click="openPosition('bottomright')" class="p-button-warning" />
</div>
</div>
<Dialog header="Header" v-model:visible="displayPosition" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :position="position" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closePosition" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closePosition" autofocus />
</template>
</Dialog>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const displayBasic = ref(false);
const displayBasic2 = ref(false);
const displayModal = ref(false);
const displayResponsive = ref(false);
const displayConfirmation = ref(false);
const displayMaximizable = ref(false);
const displayPosition = ref(false);
const position = ref('center');
const openBasic = () => {
displayBasic.value = true;
};
const closeBasic = () => {
displayBasic.value = false;
};
const openBasic2 = () => {
displayBasic2.value = true;
};
const closeBasic2 = () => {
displayBasic2.value = false;
};
const openResponsive = () => {
displayResponsive.value = true;
};
const closeResponsive = () => {
displayResponsive.value = false;
};
const openModal = () => {
displayModal.value = true;
};
const closeModal = () => {
displayModal.value = false;
}
const openConfirmation = () => {
displayConfirmation.value = true;
};
const closeConfirmation = () => {
displayConfirmation.value = false;
};
const openMaximizable = () => {
displayMaximizable.value = true;
};
const closeMaximizable = () => {
displayMaximizable.value = false;
};
const openPosition = (pos) => {
position.value = pos;
displayPosition.value = true;
};
const closePosition = () => {
displayPosition.value = false;
};
return { displayBasic, displayBasic2, displayModal, displayResponsive, displayConfirmation, displayMaximizable,
displayPosition, position, openBasic, openBasic2, closeBasic, closeBasic2, openResponsive, closeResponsive,
openModal, closeModal, openConfirmation, closeConfirmation, openMaximizable, closeMaximizable, openPosition, closePosition}
}
}
<\\/script>
<style scoped lang="scss">
.p-button {
margin: 0.3rem .5rem;
min-width: 10rem;
}
p {
margin: 0;
}
.confirmation-content {
display: flex;
align-items: center;
justify-content: center;
}
.p-dialog .p-button {
min-width: 6rem;
}
</style>`
},
'browser-source': {
tabName: 'Browser Source',
content: `<div id="app">
<h5>Basic</h5>
<p-button label="Show" icon="pi pi-external-link" @click="openBasic"></p-button>
<p-dialog header="Header" v-model:visible="displayBasic" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<p-button label="No" icon="pi pi-times" @click="closeBasic" class="p-button-text"></p-button>
<p-button label="Yes" icon="pi pi-check" @click="closeBasic" autofocus></p-button>
</template>
</p-dialog>
<p-button label="Long Content" icon="pi pi-external-link" @click="openBasic2"></p-button>
<p-dialog header="Header" v-model:visible="displayBasic2" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.</p>
<p>"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae
dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est,
qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam,
quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur,
vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?</p>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident,
similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio
cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe
eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.</p>
<template #footer>
<p-button label="No" icon="pi pi-times" @click="closeBasic2" class="p-button-text"></p-button>
<p-button label="Yes" icon="pi pi-check" @click="closeBasic2" autofocus></p-button>
</template>
</p-dialog>
<h5>Modal</h5>
<p-button label="Show" icon="pi pi-external-link" @click="openModal"></p-button>
<p-dialog header="Header" v-model:visible="displayModal" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<p-button label="No" icon="pi pi-times" @click="closeModal" class="p-button-text"></p-button>
<p-button label="Yes" icon="pi pi-check" @click="closeModal" autofocus></p-button>
</template>
</p-dialog>
<h5>Responsive</h5>
<p-button label="Show" icon="pi pi-external-link" @click="openResponsive"></p-button>
<p-dialog header="Header" v-model:visible="displayResponsive" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<p-button label="No" icon="pi pi-times" @click="closeResponsive" class="p-button-text"></p-button>
<p-button label="Yes" icon="pi pi-check" @click="closeResponsive" autofocus></p-button>
</template>
</p-dialog>
<h5>Confirmation</h5>
<p-button label="Confirm" icon="pi pi-external-link" @click="openConfirmation"></p-button>
<p-dialog header="Confirmation" v-model:visible="displayConfirmation" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '350px'}" :modal="true">
<div class="confirmation-content">
<i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem"></i>
<span>Are you sure you want to proceed?</span>
</div>
<template #footer>
<p-button label="No" icon="pi pi-times" @click="closeConfirmation" class="p-button-text"></p-button>
<p-button label="Yes" icon="pi pi-check" @click="closeConfirmation" class="p-button-text" autofocus></p-button>
</template>
</p-dialog>
<h5>Maximizable</h5>
<p-button label="Show" icon="pi pi-external-link" @click="openMaximizable"></p-button>
<p-dialog header="Header" v-model:visible="displayMaximizable" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :maximizable="true" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<p-button label="No" icon="pi pi-times" @click="closeMaximizable" class="p-button-text"></p-button>
<p-button label="Yes" icon="pi pi-check" @click="closeMaximizable" autofocus></p-button>
</template>
</p-dialog>
<h5>Position</h5>
<div class="grid p-dir-col">
<div class="col">
<p-button label="Left" icon="pi pi-arrow-right" @click="openPosition('left')" class="p-button-warning"></p-button>
<p-button label="Right" icon="pi pi-arrow-left" @click="openPosition('right')" class="p-button-warning"></p-button>
</div>
<div class="col">
<p-button label="Top" icon="pi pi-arrow-down" @click="openPosition('top')" class="p-button-warning"></p-button>
<p-button label="TopLeft" icon="pi pi-arrow-down-right" @click="openPosition('topleft')" class="p-button-warning"></p-button>
<p-button label="TopRight" icon="pi pi-arrow-down-left" @click="openPosition('topright')" class="p-button-warning"></p-button>
</div>
<div class="col">
<p-button label="Bottom" icon="pi pi-arrow-up" @click="openPosition('bottom')" class="p-button-warning"></p-button>
<p-button label="BottomLeft" icon="pi pi-arrow-up-right" @click="openPosition('bottomleft')" class="p-button-warning"></p-button>
<p-button label="BottomRight" icon="pi pi-arrow-up-left" @click="openPosition('bottomright')" class="p-button-warning"></p-button>
</div>
</div>
<p-dialog header="Header" v-model:visible="displayPosition" :breakpoints="{'960px': '75vw', '640px': '90vw'}" :style="{width: '50vw'}" :position="position" :modal="true">
<p class="m-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<template #footer>
<p-button label="No" icon="pi pi-times" @click="closePosition" class="p-button-text"></p-button>
<p-button label="Yes" icon="pi pi-check" @click="closePosition" autofocus></p-button>
</template>
</p-dialog>
</div>
<script type="module">
const { createApp, ref } = Vue;
const App = {
setup() {
const displayBasic = ref(false);
const displayBasic2 = ref(false);
const displayModal = ref(false);
const displayResponsive = ref(false);
const displayConfirmation = ref(false);
const displayMaximizable = ref(false);
const displayPosition = ref(false);
const position = ref('center');
const openBasic = () => {
displayBasic.value = true;
};
const closeBasic = () => {
displayBasic.value = false;
};
const openBasic2 = () => {
displayBasic2.value = true;
};
const closeBasic2 = () => {
displayBasic2.value = false;
};
const openResponsive = () => {
displayResponsive.value = true;
};
const closeResponsive = () => {
displayResponsive.value = false;
};
const openModal = () => {
displayModal.value = true;
};
const closeModal = () => {
displayModal.value = false;
}
const openConfirmation = () => {
displayConfirmation.value = true;
};
const closeConfirmation = () => {
displayConfirmation.value = false;
};
const openMaximizable = () => {
displayMaximizable.value = true;
};
const closeMaximizable = () => {
displayMaximizable.value = false;
};
const openPosition = (pos) => {
position.value = pos;
displayPosition.value = true;
};
const closePosition = () => {
displayPosition.value = false;
};
return { displayBasic, displayBasic2, displayModal, displayResponsive, displayConfirmation, displayMaximizable,
displayPosition, position, openBasic, openBasic2, closeBasic, closeBasic2, openResponsive, closeResponsive,
openModal, closeModal, openConfirmation, closeConfirmation, openMaximizable, closeMaximizable, openPosition, closePosition}
},
components: {
"p-dialog": primevue.dialog,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.p-button {
margin: 0.3rem .5rem;
min-width: 10rem;
}
p {
margin: 0;
}
.confirmation-content {
display: flex;
align-items: center;
justify-content: center;
}
.p-dialog .p-button {
min-width: 6rem;
}
</style>
`
}
}
};
}
};
</script>

225
pages/dialog/index.vue Executable file
View File

@ -0,0 +1,225 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Dialog</h1>
<p>Dialog is a container to display content in an overlay window.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<Button label="Show" icon="pi pi-external-link" @click="openBasic" />
<Dialog header="Header" v-model:visible="displayBasic" :breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeBasic" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closeBasic" autofocus />
</template>
</Dialog>
<Button label="Long Content" icon="pi pi-external-link" @click="openBasic2" />
<Dialog header="Header" v-model:visible="displayBasic2" :breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<p>
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur,
adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid
ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
</p>
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod
maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae
non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeBasic2" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closeBasic2" autofocus />
</template>
</Dialog>
<h5>Modal</h5>
<Button label="Show" icon="pi pi-external-link" @click="openModal" />
<Dialog header="Header" v-model:visible="displayModal" :breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }" :modal="true">
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeModal" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closeModal" autofocus />
</template>
</Dialog>
<h5>Responsive</h5>
<Button label="Show" icon="pi pi-external-link" @click="openResponsive" />
<Dialog header="Header" v-model:visible="displayResponsive" :breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeResponsive" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closeResponsive" autofocus />
</template>
</Dialog>
<h5>Confirmation</h5>
<Button label="Confirm" icon="pi pi-external-link" @click="openConfirmation" />
<Dialog header="Confirmation" v-model:visible="displayConfirmation" :breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '350px' }" :modal="true">
<div class="confirmation-content">
<i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem" />
<span>Are you sure you want to proceed?</span>
</div>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeConfirmation" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closeConfirmation" class="p-button-text" autofocus />
</template>
</Dialog>
<h5>Maximizable</h5>
<Button label="Show" icon="pi pi-external-link" @click="openMaximizable" />
<Dialog header="Header" v-model:visible="displayMaximizable" :breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }" :maximizable="true" :modal="true">
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeMaximizable" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closeMaximizable" autofocus />
</template>
</Dialog>
<h5>Position</h5>
<div class="grid flex-column">
<div class="col">
<Button label="Left" icon="pi pi-arrow-right" @click="openPosition('left')" class="p-button-warning" />
<Button label="Right" icon="pi pi-arrow-left" @click="openPosition('right')" class="p-button-warning" />
</div>
<div class="col">
<Button label="Top" icon="pi pi-arrow-down" @click="openPosition('top')" class="p-button-warning" />
<Button label="TopLeft" icon="pi pi-arrow-down-right" @click="openPosition('topleft')" class="p-button-warning" />
<Button label="TopRight" icon="pi pi-arrow-down-left" @click="openPosition('topright')" class="p-button-warning" />
</div>
<div class="col">
<Button label="Bottom" icon="pi pi-arrow-up" @click="openPosition('bottom')" class="p-button-warning" />
<Button label="BottomLeft" icon="pi pi-arrow-up-right" @click="openPosition('bottomleft')" class="p-button-warning" />
<Button label="BottomRight" icon="pi pi-arrow-up-left" @click="openPosition('bottomright')" class="p-button-warning" />
</div>
</div>
<Dialog header="Header" v-model:visible="displayPosition" :breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }" :position="position" :modal="true">
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closePosition" class="p-button-text" />
<Button label="Yes" icon="pi pi-check" @click="closePosition" autofocus />
</template>
</Dialog>
</div>
</div>
<DialogDoc />
</div>
</template>
<script>
import DialogDoc from './DialogDoc';
export default {
data() {
return {
displayBasic: false,
displayBasic2: false,
displayModal: false,
displayResponsive: false,
displayConfirmation: false,
displayMaximizable: false,
displayPosition: false,
position: 'center'
};
},
methods: {
openBasic() {
this.displayBasic = true;
},
closeBasic() {
this.displayBasic = false;
},
openBasic2() {
this.displayBasic2 = true;
},
closeBasic2() {
this.displayBasic2 = false;
},
openResponsive() {
this.displayResponsive = true;
},
closeResponsive() {
this.displayResponsive = false;
},
openModal() {
this.displayModal = true;
},
closeModal() {
this.displayModal = false;
},
openConfirmation() {
this.displayConfirmation = true;
},
closeConfirmation() {
this.displayConfirmation = false;
},
openMaximizable() {
this.displayMaximizable = true;
},
closeMaximizable() {
this.displayMaximizable = false;
},
openPosition(position) {
this.position = position;
this.displayPosition = true;
},
closePosition() {
this.displayPosition = false;
}
},
components: {
DialogDoc: DialogDoc
}
};
</script>
<style scoped lang="scss">
.p-button {
margin: 0 0.5rem 0 0;
min-width: 10rem;
}
p {
margin: 0;
}
.confirmation-content {
display: flex;
align-items: center;
justify-content: center;
}
.p-dialog .p-button {
min-width: 6rem;
}
</style>

View File

@ -0,0 +1,657 @@
<template>
<AppDoc name="DividerDemo" :sources="sources" github="divider/DividerDemo.vue">
<h5>Import via Module</h5>
<pre v-code.script><code>
import Divider from 'primevue/divider';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/divider/divider.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Divider has two orientations defined with the <i>layout</i> property, default is "horizontal" and the alternative is "vertical".</p>
<pre v-code><code>
&lt;div&gt;Content 1&lt;/div&gt;
&lt;Divider /&gt;
&lt;div&gt;Content 2&lt;/div&gt;
</code></pre>
<h5>Border Style</h5>
<p>Style of the border is configured with the <i>type</i> property and supports 3 values; default is "solid" and other possibilities are "dashed" and "dotted".</p>
<pre v-code><code>
&lt;div&gt;Content 1&lt;/div&gt;
&lt;Divider type="dashed"/&gt;
&lt;div&gt;Content 2&lt;/div&gt;
</code></pre>
<h5>Vertical Divider</h5>
<p>Vertical divider is enabled by setting the <i>layout</i> property as "vertical".</p>
<pre v-code><code>
&lt;div class="flex"&gt;
&lt;div&gt;Content 1&lt;/div&gt;
&lt;Divider layout="vertical" /&gt;
&lt;div&gt;Content 2&lt;/div&gt;
&lt;Divider layout="vertical" /&gt;
&lt;div&gt;Content 3&lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h5>Content</h5>
<p>
Any content placed inside is rendered within the boundaries of the divider. In addition, location of the content is configured with the <i>align</i> property. In horizontal layout, alignment options are "left", "center" and "right"
whereas vertical mode supports "top", "center" and "bottom".
</p>
<pre v-code><code>
&lt;div&gt;Content 1&lt;/div&gt;
&lt;Divider align="left"&gt;
&lt;div class="inline-flex align-items-center"&gt;
&lt;i class="pi pi-user mr-2"&gt;&lt;/i&gt;
&lt;b&gt;Icon&lt;/b&gt;
&lt;/div&gt;
&lt;/Divider&gt;
&lt;div&gt;Content 2&lt;/div&gt;
&lt;Divider align="center"&gt;
&lt;span class="p-tag"&gt;Badge&lt;/span&gt;
&lt;/Divider&gt;
&lt;div&gt;Content 3&lt;/div&gt;
&lt;Divider align="right"&gt;
&lt;Button label="Button" icon="pi pi-search" class="p-button-outlined"&gt;&lt;/Button&gt;
&lt;/Divider&gt;
&lt;div&gt;Content 4&lt;/div&gt;
</code></pre>
<h5>Properties</h5>
<p>Any property as style and class are passed to the main container element. Following are the additional properties to configure the component.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>align</td>
<td>string</td>
<td>null</td>
<td>Alignment of the content, options are "left", "center", "right" for horizontal layout and "top", "center", "bottom" for vertical.</td>
</tr>
<tr>
<td>layout</td>
<td>string</td>
<td>horizontal</td>
<td>Specifies the orientation, valid values are "horizontal" and "vertical".</td>
</tr>
<tr>
<td>type</td>
<td>string</td>
<td>solid</td>
<td>Border style type, default is "solid" and other options are "dashed" and "dotted".</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <router-link to="/theming">theming</router-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-divider</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-divider-horizontal</td>
<td>Container element in horizontal layout.</td>
</tr>
<tr>
<td>p-divider-vertical</td>
<td>Container element in vertical layout.</td>
</tr>
<tr>
<td>p-divider-solid</td>
<td>Container element with solid border.</td>
</tr>
<tr>
<td>p-divider-dashed</td>
<td>Container element with dashed border.</td>
</tr>
<tr>
<td>p-divider-dotted</td>
<td>Container element with dotted border.</td>
</tr>
<tr>
<td>p-divider-left</td>
<td>Container element with content aligned to left.</td>
</tr>
<tr>
<td>p-divider-right</td>
<td>Container element with content aligned to right.</td>
</tr>
<tr>
<td>p-divider-center</td>
<td>Container element with content aligned to center.</td>
</tr>
<tr>
<td>p-divider-bottom</td>
<td>Container element with content aligned to bottom.</td>
</tr>
<tr>
<td>p-divider-top</td>
<td>Container element with content aligned to top.</td>
</tr>
</tbody>
</table>
</div>
<h5>Accessibility</h5>
<DevelopmentSection>
<h6>Screen Reader</h6>
<p>Divider uses a <i>separator</i> role with <i>aria-orientation</i> set to either "horizontal" or "vertical".</p>
<h5>Keyboard Support</h5>
<p>Component does not include any interactive elements.</p>
</DevelopmentSection>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<div class="card">
<h5>Basic</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider />
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider />
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<Divider />
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Text with Dashed Style</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider align="left" type="dashed">
<b>Left</b>
</Divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider align="center" type="dashed">
<b>Center</b>
</Divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<Divider align="right" type="dashed">
<b>Right</b>
</Divider>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Content</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider align="left">
<div class="inline-flex align-items-center">
<i class="pi pi-user mr-2"></i>
<b>Icon</b>
</div>
</Divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider align="center">
<span class="p-tag">Badge</span>
</Divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<Divider align="right">
<Button label="Button" icon="pi pi-search" class="p-button-outlined"></Button>
</Divider>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Vertical</h5>
<div class="flex">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider layout="vertical" />
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider layout="vertical" />
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</div>
</div>
<div class="card">
<h5>Vertical with Content</h5>
<div class="grid">
<div class="col-5 flex align-items-center justify-content-center">
<div class="p-fluid">
<div class="field">
<label for="username">Username</label>
<InputText id="username" type="text" />
</div>
<div class="field">
<label for="password">Password</label>
<InputText id="password" type="password" />
</div>
<Button label="Login"></Button>
</div>
</div>
<div class="col-2">
<Divider layout="vertical">
<b>OR</b>
</Divider>
</div>
<div class="col-5 flex align-items-center justify-content-center">
<Button label="Sign Up" icon="pi pi-user-plus" class="p-button-success"></Button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<div class="card">
<h5>Basic</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider />
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider />
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<Divider />
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Text with Dashed Style</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider align="left" type="dashed">
<b>Left</b>
</Divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider align="center" type="dashed">
<b>Center</b>
</Divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<Divider align="right" type="dashed">
<b>Right</b>
</Divider>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Content</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider align="left">
<div class="inline-flex align-items-center">
<i class="pi pi-user mr-2"></i>
<b>Icon</b>
</div>
</Divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider align="center">
<span class="p-tag">Badge</span>
</Divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<Divider align="right">
<Button label="Button" icon="pi pi-search" class="p-button-outlined"></Button>
</Divider>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Vertical</h5>
<div class="flex">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Divider layout="vertical" />
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<Divider layout="vertical" />
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</div>
</div>
<div class="card">
<h5>Vertical with Content</h5>
<div class="grid">
<div class="col-5 flex align-items-center justify-content-center">
<div class="p-fluid">
<div class="field">
<label for="username">Username</label>
<InputText id="username" type="text" />
</div>
<div class="field">
<label for="password">Password</label>
<InputText id="password" type="password" />
</div>
<Button label="Login"></Button>
</div>
</div>
<div class="col-2">
<Divider layout="vertical">
<b>OR</b>
</Divider>
</div>
<div class="col-5 flex align-items-center justify-content-center">
<Button label="Sign Up" icon="pi pi-user-plus" class="p-button-success"></Button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/divider/divider.min.js"><\\/script>`,
content: `<div id="app">
<div class="card">
<h5>Basic</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p-divider></p-divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<p-divider></p-divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<p-divider></p-divider>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Text with Dashed Style</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p-divider align="left" type="dashed">
<b>Left</b>
</p-divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<p-divider align="center" type="dashed">
<b>Center</b>
</p-divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<p-divider align="right" type="dashed">
<b>Right</b>
</p-divider>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Content</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p-divider align="left">
<div class="inline-flex align-items-center">
<i class="pi pi-user mr-2"></i>
<b>Icon</b>
</div>
</p-divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<p-divider align="center">
<span class="p-tag">Badge</span>
</p-divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
<p-divider align="right">
<p-button label="Button" icon="pi pi-search" class="p-button-outlined"></p-button>
</p-divider>
<p>Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur
a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.
Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.</p>
</div>
<div class="card">
<h5>Vertical</h5>
<div class="flex">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p-divider layout="vertical"></p-divider>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.</p>
<p-divider layout="vertical"></p-divider>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati
cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.
Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.</p>
</div>
</div>
<div class="card">
<h5>Vertical with Content</h5>
<div class="grid">
<div class="col-5 flex align-items-center justify-content-center">
<div class="p-fluid">
<div class="field">
<label for="username">Username</label>
<p-inputtext id="username" type="text"></p-inputtext>
</div>
<div class="field">
<label for="password">Password</label>
<p-inputtext id="password" type="password"></p-inputtext>
</div>
<p-button label="Login"></p-button>
</div>
</div>
<div class="col-2">
<p-divider layout="vertical">
<b>OR</b>
</p-divider>
</div>
<div class="col-5 flex align-items-center justify-content-center">
<p-button label="Sign Up" icon="pi pi-user-plus" class="p-button-success"></p-button>
</div>
</div>
</div>
</div>
<script type="module">
const { createApp } = Vue;
const App = {
components: {
"p-divider": primevue.divider,
"p-inputtext": primevue.inputtext,
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
`
}
}
};
}
};
</script>

178
pages/divider/index.vue Normal file
View File

@ -0,0 +1,178 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Divider</h1>
<p>Divider is used to separate contents.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<Divider />
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
<Divider />
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui
officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
<Divider />
<p>
Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis
voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.
</p>
</div>
<div class="card">
<h5>Text with Dashed Style</h5>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<Divider align="left" type="dashed">
<b>Left</b>
</Divider>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
<Divider align="center" type="dashed">
<b>Center</b>
</Divider>
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui
officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
<Divider align="right" type="dashed">
<b>Right</b>
</Divider>
<p>
Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis
voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.
</p>
</div>
<div class="card">
<h5>Content</h5>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<Divider align="left">
<div class="inline-flex align-items-center">
<i class="pi pi-user mr-2"></i>
<b>Icon</b>
</div>
</Divider>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
<Divider align="center">
<span class="p-tag">Badge</span>
</Divider>
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui
officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
<Divider align="right">
<Button label="Button" icon="pi pi-search" class="p-button-outlined"></Button>
</Divider>
<p>
Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis
voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. Donec vel volutpat ipsum. Integer nunc magna, posuere ut tincidunt eget, egestas vitae sapien. Morbi dapibus luctus odio.
</p>
</div>
<div class="card">
<h5>Vertical</h5>
<div class="flex">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<Divider layout="vertical" />
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non numquam eius modi.
</p>
<Divider layout="vertical" />
<p>
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus.
</p>
</div>
</div>
<div class="card">
<h5>Vertical with Content</h5>
<div class="grid">
<div class="col-5 flex align-items-center justify-content-center">
<div class="p-fluid">
<div class="field">
<label for="username">Username</label>
<InputText id="username" type="text" />
</div>
<div class="field">
<label for="password">Password</label>
<InputText id="password" type="password" />
</div>
<Button label="Login"></Button>
</div>
</div>
<div class="col-2">
<Divider layout="vertical">
<b>OR</b>
</Divider>
</div>
<div class="col-5 flex align-items-center justify-content-center">
<Button label="Sign Up" icon="pi pi-user-plus" class="p-button-success"></Button>
</div>
</div>
</div>
</div>
<DividerDoc />
</div>
</template>
<script>
import DividerDoc from './DividerDoc';
export default {
components: {
DividerDoc: DividerDoc
}
};
</script>

1468
pages/dock/DockDoc.vue Normal file

File diff suppressed because it is too large Load Diff

404
pages/dock/index.vue Normal file
View File

@ -0,0 +1,404 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Dock</h1>
<p>Dock is a navigation component consisting of menuitems.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation dock-demo">
<Toast position="top-center" group="tc" />
<h5>Basic</h5>
<div class="dock-window">
<Dock :model="dockBasicItems" position="bottom">
<template #icon="{ item }">
<img :alt="item.label" :src="item.icon" style="width: 100%" />
</template>
</Dock>
<Dock :model="dockBasicItems" position="top">
<template #icon="{ item }">
<img :alt="item.label" :src="item.icon" style="width: 100%" />
</template>
</Dock>
<Dock :model="dockBasicItems" position="left">
<template #icon="{ item }">
<img :alt="item.label" :src="item.icon" style="width: 100%" />
</template>
</Dock>
<Dock :model="dockBasicItems" position="right">
<template #icon="{ item }">
<img :alt="item.label" :src="item.icon" style="width: 100%" />
</template>
</Dock>
</div>
<h5>Advanced</h5>
<Menubar :model="menubarItems">
<template #start>
<i class="pi pi-apple"></i>
</template>
<template #end>
<i class="pi pi-video" />
<i class="pi pi-wifi" />
<i class="pi pi-volume-up" />
<span>Fri 13:07</span>
<i class="pi pi-search" />
<i class="pi pi-bars" />
</template>
</Menubar>
<div class="dock-window dock-advanced">
<Dock :model="dockItems">
<template #item="{ item }">
<a href="#" class="p-dock-action" v-tooltip.top="item.label" @click="onDockItemClick($event, item)">
<img :alt="item.label" :src="item.icon" style="width: 100%" />
</a>
</template>
</Dock>
<Dialog v-model:visible="displayTerminal" header="Terminal" :breakpoints="{ '960px': '50vw' }" :style="{ width: '40vw' }" :maximizable="true">
<Terminal welcomeMessage="Welcome to PrimeVue(cmd: 'date', 'greet {0}', 'random' and 'clear')" prompt="primevue $" />
</Dialog>
<Dialog v-model:visible="displayFinder" header="Finder" :breakpoints="{ '960px': '50vw' }" :style="{ width: '40vw' }" :maximizable="true">
<Tree :value="nodes" />
</Dialog>
<Galleria v-model:visible="displayPhotos" :value="images" :responsiveOptions="responsiveOptions" :numVisible="2" containerStyle="width: 400px" :circular="true" :fullScreen="true" :showThumbnails="false" :showItemNavigators="true">
<template #item="slotProps">
<img :src="slotProps.item.itemImageSrc" :alt="slotProps.item.alt" style="width: 100%" />
</template>
</Galleria>
</div>
</div>
<DockDoc />
</div>
</template>
<script>
import NodeService from '../../service/NodeService';
import PhotoService from '../../service/PhotoService';
import TerminalService from 'primevue/terminalservice';
import DockDoc from './DockDoc.vue';
export default {
data() {
return {
displayFinder: false,
displayTerminal: false,
displayPhotos: false,
images: null,
nodes: null,
imgErrorPath: 'https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png',
dockItems: [
{
label: 'Finder',
icon: 'demo/images/dock/finder.svg',
command: () => {
this.displayFinder = true;
}
},
{
label: 'Terminal',
icon: 'demo/images/dock/terminal.svg',
command: () => {
this.displayTerminal = true;
}
},
{
label: 'App Store',
icon: 'demo/images/dock/appstore.svg',
command: () => {
this.$toast.add({ severity: 'error', summary: 'An unexpected error occurred while signing in.', detail: 'UNTRUSTED_CERT_TITLE', group: 'tc', life: 3000 });
}
},
{
label: 'Safari',
icon: 'demo/images/dock/safari.svg',
command: () => {
this.$toast.add({ severity: 'warn', summary: 'Safari has stopped working', group: 'tc', life: 3000 });
}
},
{
label: 'Photos',
icon: 'demo/images/dock/photos.svg',
command: () => {
this.displayPhotos = true;
}
},
{
label: 'GitHub',
icon: 'demo/images/dock/github.svg'
},
{
label: 'Trash',
icon: 'demo/images/dock/trash.png',
command: () => {
this.$toast.add({ severity: 'info', summary: 'Empty Trash', life: 3000 });
}
}
],
dockBasicItems: [
{
label: 'Finder',
icon: 'demo/images/dock/finder.svg'
},
{
label: 'App Store',
icon: 'demo/images/dock/appstore.svg'
},
{
label: 'Photos',
icon: 'demo/images/dock/photos.svg'
},
{
label: 'Trash',
icon: 'demo/images/dock/trash.png'
}
],
menubarItems: [
{
label: 'Finder',
class: 'menubar-root'
},
{
label: 'File',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-plus',
items: [
{
label: 'Bookmark',
icon: 'pi pi-fw pi-bookmark'
},
{
label: 'Video',
icon: 'pi pi-fw pi-video'
}
]
},
{
label: 'Delete',
icon: 'pi pi-fw pi-trash'
},
{
separator: true
},
{
label: 'Export',
icon: 'pi pi-fw pi-external-link'
}
]
},
{
label: 'Edit',
items: [
{
label: 'Left',
icon: 'pi pi-fw pi-align-left'
},
{
label: 'Right',
icon: 'pi pi-fw pi-align-right'
},
{
label: 'Center',
icon: 'pi pi-fw pi-align-center'
},
{
label: 'Justify',
icon: 'pi pi-fw pi-align-justify'
}
]
},
{
label: 'Users',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-user-plus'
},
{
label: 'Delete',
icon: 'pi pi-fw pi-user-minus'
},
{
label: 'Search',
icon: 'pi pi-fw pi-users',
items: [
{
label: 'Filter',
icon: 'pi pi-fw pi-filter',
items: [
{
label: 'Print',
icon: 'pi pi-fw pi-print'
}
]
},
{
icon: 'pi pi-fw pi-bars',
label: 'List'
}
]
}
]
},
{
label: 'Events',
items: [
{
label: 'Edit',
icon: 'pi pi-fw pi-pencil',
items: [
{
label: 'Save',
icon: 'pi pi-fw pi-calendar-plus'
},
{
label: 'Delete',
icon: 'pi pi-fw pi-calendar-minus'
}
]
},
{
label: 'Archieve',
icon: 'pi pi-fw pi-calendar-times',
items: [
{
label: 'Remove',
icon: 'pi pi-fw pi-calendar-minus'
}
]
}
]
},
{
label: 'Quit'
}
],
responsiveOptions: [
{
breakpoint: '1024px',
numVisible: 3
},
{
breakpoint: '768px',
numVisible: 2
},
{
breakpoint: '560px',
numVisible: 1
}
]
};
},
nodeService: null,
photoService: null,
created() {
this.nodeService = new NodeService();
this.photoService = new PhotoService();
},
mounted() {
this.photoService.getImages().then((data) => (this.images = data));
this.nodeService.getTreeNodes().then((data) => (this.nodes = data));
TerminalService.on('command', this.commandHandler);
},
beforeUnmount() {
TerminalService.off('command', this.commandHandler);
},
methods: {
onDockItemClick(event, item) {
if (item.command) {
item.command();
}
event.preventDefault();
},
commandHandler(text) {
let response;
let argsIndex = text.indexOf(' ');
let command = argsIndex !== -1 ? text.substring(0, argsIndex) : text;
switch (command) {
case 'date':
response = 'Today is ' + new Date().toDateString();
break;
case 'greet':
response = 'Hola ' + text.substring(argsIndex + 1);
break;
case 'random':
response = Math.floor(Math.random() * 100);
break;
default:
response = 'Unknown command: ' + command;
}
TerminalService.emit('response', response);
}
},
components: {
DockDoc: DockDoc
}
};
</script>
<style scoped lang="scss">
::v-deep(.dock-demo) {
.dock-window {
width: 100%;
height: 450px;
position: relative;
background-image: url('../../assets/images/dock/window.jpg');
background-repeat: no-repeat;
background-size: cover;
z-index: 1;
}
.p-dock {
z-index: 1000;
}
.p-menubar {
padding-top: 0;
padding-bottom: 0;
border-radius: 0;
.menubar-root {
font-weight: bold;
padding: 0 1rem;
}
.p-menuitem-link {
padding: 0.5rem 0.75rem;
}
.p-menubar-root-list > .p-menuitem > .p-menuitem-link {
padding: 0.5rem 0.75rem;
> .p-submenu-icon {
display: none;
}
}
.p-menubar-end {
span,
i {
padding: 0 0.75rem;
}
}
.p-submenu-list {
z-index: 2;
}
}
}
</style>

1296
pages/dropdown/DropdownDoc.vue Executable file

File diff suppressed because it is too large Load Diff

183
pages/dropdown/index.vue Executable file
View File

@ -0,0 +1,183 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Dropdown</h1>
<p>Dropdown is used to select an item from a list of options.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<h5>Basic</h5>
<Dropdown v-model="selectedCity1" :options="cities" optionLabel="name" optionValue="code" placeholder="Select a City" />
<h5>Editable</h5>
<Dropdown v-model="selectedCity2" :options="cities" optionLabel="name" :editable="true" />
<h5>Grouped</h5>
<Dropdown v-model="selectedGroupedCity" :options="groupedCities" optionLabel="label" optionGroupLabel="label" optionGroupChildren="items">
<template #optiongroup="slotProps">
<div class="flex align-items-center country-item">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.option.code.toLowerCase()" width="18" />
<div>{{ slotProps.option.label }}</div>
</div>
</template>
</Dropdown>
<h5>Advanced with Templating, Filtering and Clear Icon</h5>
<Dropdown v-model="selectedCountry" :options="countries" optionLabel="name" :filter="true" placeholder="Select a Country" :showClear="true">
<template #value="slotProps">
<div class="country-item country-item-value" v-if="slotProps.value">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.value.code.toLowerCase()" />
<div>{{ slotProps.value.name }}</div>
</div>
<span v-else>
{{ slotProps.placeholder }}
</span>
</template>
<template #option="slotProps">
<div class="country-item">
<img src="../../assets/images/flag_placeholder.png" :class="'flag flag-' + slotProps.option.code.toLowerCase()" />
<div>{{ slotProps.option.name }}</div>
</div>
</template>
</Dropdown>
<h5>Loading State</h5>
<Dropdown placeholder="Loading..." loading></Dropdown>
<h5>Virtual Scroll (100000 Items)</h5>
<Dropdown v-model="selectedItem1" :options="items" optionLabel="label" optionValue="value" :virtualScrollerOptions="{ itemSize: 38 }" placeholder="Select Item"></Dropdown>
<h5>Virtual Scroll (100000 Items) and Lazy</h5>
<Dropdown
v-model="selectedItem2"
:options="lazyItems"
optionLabel="label"
optionValue="value"
:virtualScrollerOptions="{ lazy: true, onLazyLoad: onLazyLoad, itemSize: 38, showLoader: true, loading: loading, delay: 250 }"
placeholder="Select Item"
>
<template v-slot:loader="{ options }">
<div class="flex align-items-center p-2" style="height: 38px">
<Skeleton :width="options.even ? '60%' : '50%'" height="1rem" />
</div>
</template>
</Dropdown>
</div>
</div>
<DropdownDoc />
</div>
</template>
<script>
import DropdownDoc from './DropdownDoc';
export default {
data() {
return {
selectedCity1: null,
selectedCity2: null,
selectedCountry: null,
selectedGroupedCity: null,
selectedItem1: null,
selectedItem2: null,
loading: false,
cities: [
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
],
countries: [
{ name: 'Australia', code: 'AU' },
{ name: 'Brazil', code: 'BR' },
{ name: 'China', code: 'CN' },
{ name: 'Egypt', code: 'EG' },
{ name: 'France', code: 'FR' },
{ name: 'Germany', code: 'DE' },
{ name: 'India', code: 'IN' },
{ name: 'Japan', code: 'JP' },
{ name: 'Spain', code: 'ES' },
{ name: 'United States', code: 'US' }
],
groupedCities: [
{
label: 'Germany',
code: 'DE',
items: [
{ label: 'Berlin', value: 'Berlin' },
{ label: 'Frankfurt', value: 'Frankfurt' },
{ label: 'Hamburg', value: 'Hamburg' },
{ label: 'Munich', value: 'Munich' }
]
},
{
label: 'USA',
code: 'US',
items: [
{ label: 'Chicago', value: 'Chicago' },
{ label: 'Los Angeles', value: 'Los Angeles' },
{ label: 'New York', value: 'New York' },
{ label: 'San Francisco', value: 'San Francisco' }
]
},
{
label: 'Japan',
code: 'JP',
items: [
{ label: 'Kyoto', value: 'Kyoto' },
{ label: 'Osaka', value: 'Osaka' },
{ label: 'Tokyo', value: 'Tokyo' },
{ label: 'Yokohama', value: 'Yokohama' }
]
}
],
items: Array.from({ length: 100000 }, (_, i) => ({ label: `Item #${i}`, value: i })),
lazyItems: Array.from({ length: 100000 })
};
},
loadLazyTimeout: null,
methods: {
onLazyLoad(event) {
this.loading = true;
if (this.loadLazyTimeout) {
clearTimeout(this.loadLazyTimeout);
}
//imitate delay of a backend call
this.loadLazyTimeout = setTimeout(() => {
const { first, last } = event;
const lazyItems = [...this.lazyItems];
for (let i = first; i < last; i++) {
lazyItems[i] = { label: `Item #${i}`, value: i };
}
this.lazyItems = lazyItems;
this.loading = false;
}, Math.random() * 1000 + 250);
}
},
components: {
DropdownDoc: DropdownDoc
}
};
</script>
<style lang="scss" scoped>
.p-dropdown {
width: 14rem;
}
.country-item-value {
img.flag {
width: 17px;
}
}
</style>

View File

@ -0,0 +1,68 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Dynamic Dialog</h1>
<p>Dialogs can be created dynamically with any component as the content using a DialogService.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation">
<div class="card">
<Button label="Select a Product" icon="pi pi-search" @click="showProducts" />
<DynamicDialog />
</div>
</div>
<DynamicDialogDoc />
</div>
</template>
<script>
import { h } from 'vue';
import Button from 'primevue/button';
import ProductListDemo from './ProductListDemo';
import DynamicDialogDoc from './DynamicDialogDoc.vue';
export default {
methods: {
showProducts() {
const dialogRef = this.$dialog.open(ProductListDemo, {
props: {
header: 'Product List',
style: {
width: '50vw'
},
breakpoints: {
'960px': '75vw',
'640px': '90vw'
},
modal: true
},
templates: {
footer: () => {
return [
h(Button, { label: 'No', icon: 'pi pi-times', onClick: () => dialogRef.close({ buttonType: 'No' }), class: 'p-button-text' }),
h(Button, { label: 'Yes', icon: 'pi pi-check', onClick: () => dialogRef.close({ buttonType: 'Yes' }), autofocus: true })
];
}
},
onClose: (options) => {
const data = options.data;
if (data) {
const buttonType = data.buttonType;
const summary_and_detail = buttonType ? { summary: 'No Product Selected', detail: `Pressed '${buttonType}' button` } : { summary: 'Product Selected', detail: data.name };
this.$toast.add({ severity: 'info', ...summary_and_detail, life: 3000 });
}
}
});
}
},
components: {
DynamicDialogDoc: DynamicDialogDoc
}
};
</script>

View File

@ -0,0 +1,807 @@
<template>
<AppDoc name="DynamicDialogDemo" :sources="sources" :extFiles="extFiles" :service="['ProductService']" :data="['products-small']" github="dynamicdialog/DynamicDialogDemo.vue">
<h5>DialogService</h5>
<p>Dynamic dialogs require the <i>DialogService</i> to be configured globally.</p>
<pre v-code.script><code>
import {createApp} from 'vue';
import DialogService from 'primevue/dialogservice';
const app = createApp(App);
app.use(DialogService);
</code></pre>
<h5>Import via Module</h5>
<pre v-code.script><code>
import DynamicDialog from 'primevue/dynamicdialog';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
&lt;script src="https://unpkg.com/primevue@^3/dynamicdialog/dynamicdialog.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>Ideal location of a DynamicDialog is the main application template so that it can be used by any component within the application.</p>
<pre v-code><code>
&lt;template&gt;
&lt;DynamicDialog /&gt;
&lt;template&gt;
</code></pre>
<h5>Options API</h5>
<p><i>$dialog</i> is available as a property in the application instance.</p>
<pre v-code.script><code>
const dialogRef = this.$dialog;
</code></pre>
<h5>Composition API</h5>
<p>The service can be injected with the <i>useDialog</i> function.</p>
<pre v-code.script><code>
import { useDialog } from 'primevue/usedialog';
const dialog = useDialog();
</code></pre>
<h5>Opening a Dialog</h5>
<p>The <i>open</i> function of the <i>DialogService</i> is used to open a Dialog. First parameter is the component to load and second one is the configuration object to customize the Dialog.</p>
<h6>Options API</h6>
<pre v-code.script><code>
import ProductListDemo from './ProductListDemo';
export default {
methods:{
showProducts() {
this.$dialog.open(ProductListDemo, {});
}
}
}
</code></pre>
<h6>Composition API</h6>
<pre v-code.script><code>
import ProductListDemo from './ProductListDemo';
import { useDialog } from 'primevue/usedialog';
export default {
methods:{
showProducts() {
const dialog = useDialog();
dialog.open(ProductListDemo, {});
}
}
}
</code></pre>
<h5>Closing a Dialog</h5>
<p>The <i>close</i> function of the <i>dialogRef</i> is used to hide a Dialog. The <i>dialogRef</i> is injected to the component that is loaded by the dialog.</p>
<h6>Options API</h6>
<pre v-code.script><code>
export default {
inject: ['dialogRef'],
methods:{
closeDialog() {
this.dialogRef.close();
}
}
}
</code></pre>
<h6>Composition API</h6>
<pre v-code.script><code>
import { inject } from 'vue'
export default {
methods:{
closeDialog() {
const dialogRef = inject('dialogRef');
dialogRef.value.close();
}
}
}
</code></pre>
<h5>Passing Data</h5>
<p>Data can be passed to the component that is loaded by the Dialog and also from the component back to the caller component. Use the <i>open</i> function and pass your parameters with the <i>data</i> property in the options object.</p>
<pre v-code.script><code>
this.$dialog.open(ProductListDemo, {
data: {
user: 'primetime'
}
};
</code></pre>
<pre v-code.script><code>
export default {
inject: ['dialogRef'],
mounted:{
const params = this.dialogRef.data; //{user: 'primetime'}
}
}
</code></pre>
<p>Similarly when hiding a Dialog, any parameter passed to the <i>close</i> function is received from the <i>onClose</i> callback defined by the <i>open</i> function at the caller.</p>
<pre v-code.script><code>
this.$dialog.open(ProductListDemo, {
onClose(options) {
const callbackParams = options.data; //{id: 12}
}
);
</code></pre>
<pre v-code.script><code>
export default {
inject: ['dialogRef'],
methods:{
closeDialog() {
this.dialogRef.close({id: 12});
}
}
}
</code></pre>
<h5>Customizing a Dialog</h5>
<p><i>props</i> option is used to customize the dynamically generated Dialog, refer to the <router-link to="/dialog">Dialog</router-link> documentation for the whole list of options.</p>
<pre v-code.script><code>
import { h } from 'vue';
import Button from 'primevue/button';
import ProductListDemo from './ProductListDemo';
export default {
methods:{
showProducts() {
const dialogRef = this.$dialog.open(ProductListDemo, {
props: {
header: 'Product List',
style: {
width: '50vw',
},
breakpoints:{
'960px': '75vw',
'640px': '90vw'
},
modal: true
},
templates: {
footer: () => {
return [
h(Button, { label: "No", icon: "pi pi-times", onClick: () => dialogRef.close(), class: "p-button-text" }),
h(Button, { label: "Yes", icon: "pi pi-check", onClick: () => dialogRef.close(), autofocus: true})
]
}
},
onClose: (options) => {
const data = options.data;
if (data) {
this.$toast.add({ severity:'info', summary: 'Info Message', detail:'Order submitted', life: 3000 });
}
}
});
}
}
}
</code></pre>
<h5>DialogService API</h5>
<p>DialogService is the main entry point to open a dialog and load any content within.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>open</td>
<td>
content: The component to load<br />
options: Configuration of the Dialog
</td>
<td>Creates a dialog dynamically with the given options and loads the component. See the <i>Dialog Open Configuration API</i> section below for the avaiable properties.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dialog Open Configuration API</h5>
<p>Options to configure a dynamically loaded Dialog including Dialog props, data to pass and callback to execute on hide.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>props</td>
<td>object</td>
<td>null</td>
<td>Properties of a dialog.</td>
</tr>
<tr>
<td>data</td>
<td>object</td>
<td>null</td>
<td>Data to pass to the loaded component.</td>
</tr>
<tr>
<td>templates</td>
<td>object</td>
<td>null</td>
<td>Templates of a dialog including, <strong>header</strong> and <strong>footer</strong>.</td>
</tr>
<tr>
<td>onClose</td>
<td>function</td>
<td>null</td>
<td>Function callback to invoke when dialog is closed.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dialog Ref API</h5>
<p>Reference to the dynamic dialog that can be used to access the passed data and close the dialog with the option of passing data back to the caller.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>content</td>
<td>object</td>
<td>null</td>
<td>Loaded content of a dialog.</td>
</tr>
<tr>
<td>options</td>
<td>object</td>
<td>null</td>
<td>Options used to open a dialog.</td>
</tr>
<tr>
<td>data</td>
<td>object</td>
<td>null</td>
<td>Data passed to the dialog.</td>
</tr>
<tr>
<td>close</td>
<td>function</td>
<td>null</td>
<td>Function to close a dialog.</td>
</tr>
</tbody>
</table>
</div>
</AppDoc>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div>
<Button label="Show" @click="onShow" />
<DynamicDialog />
</div>
</template>
<script>
import { h } from 'vue';
import Button from 'primevue/button';
import ProductListDemo from './components/ProductListDemo';
export default {
methods:{
onShow() {
const dialogRef = this.$dialog.open(ProductListDemo, {
props: {
header: 'Product List',
style: {
width: '50vw',
},
breakpoints:{
'960px': '75vw',
'640px': '90vw'
},
modal: true
},
templates: {
footer: () => {
return [
h(Button, { label: "No", icon: "pi pi-times", onClick: () => dialogRef.close({ buttonType: 'No' }), class: "p-button-text" }),
h(Button, { label: "Yes", icon: "pi pi-check", onClick: () => dialogRef.close({ buttonType: 'Yes' }), autofocus: true })
]
}
},
onClose: (options) => {
const data = options.data;
if (data) {
const buttonType = data.buttonType;
const summary_and_detail = buttonType ? { summary: 'No Product Selected', detail: \`Pressed '\${buttonType}' button\` } : { summary: 'Product Selected', detail: data.name };
this.$toast.add({ severity:'info', ...summary_and_detail, life: 3000 });
}
}
});
}
}
}
<\\/script>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div>
<Button label="Show" @click="showProducts" />
<Toast />
<DynamicDialog />
</div>
</template>
<script>
import { h } from 'vue';
import { useDialog } from 'primevue/usedialog';
import { useToast } from 'primevue/usetoast';
import Button from 'primevue/button';
import ProductListDemo from './components/ProductListDemo';
export default {
setup() {
const dialog = useDialog();
const toast = useToast();
const showProducts = () => {
const dialogRef = dialog.open(ProductListDemo, {
props: {
header: 'Product List',
style: {
width: '50vw',
},
breakpoints:{
'960px': '75vw',
'640px': '90vw'
},
modal: true
},
templates: {
footer: () => {
return [
h(Button, { label: "No", icon: "pi pi-times", onClick: () => dialogRef.close({ buttonType: 'No' }), class: "p-button-text" }),
h(Button, { label: "Yes", icon: "pi pi-check", onClick: () => dialogRef.close({ buttonType: 'Yes' }), autofocus: true})
]
}
},
onClose: (options) => {
const data = options.data;
if (data) {
const buttonType = data.buttonType;
const summary_and_detail = buttonType ? { summary: 'No Product Selected', detail: \`Pressed '\${buttonType}' button\` } : { summary: 'Product Selected', detail: data.name };
toast.add({ severity:'info', ...summary_and_detail, life: 3000 });
}
}
});
}
return { dialog, showProducts }
}
}
<\\/script>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/dynamicdialog/dynamicdialog.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/dialogservice/dialogservice.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toast/toast.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/toastservice/toastservice.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/datatable/datatable.min.js"><\\/script>
<script src="https://unpkg.com/primevue@^3/column/column.min.js"><\\/script>
<script src="./ProductService.js"><\\/script>`,
content: `<div id="app">
<p-button label="Show" @click="showProducts"></p-button>
<p-toast></p-toast>
<p-dynamicdialog></p-dynamicdialog>
</div>
<script type="module">
const { createApp } = Vue;
const { useDialog } = primevue.usedialog;
const { useToast } = primevue.usetoast;
const App = {
setup() {
const dialog = useDialog();
const toast = useToast();
const showProducts = () => {
const dialogRef = dialog.open(ProductListDemo, {
props: {
header: 'Product List',
style: {
width: '50vw',
},
breakpoints:{
'960px': '75vw',
'640px': '90vw'
},
modal: true
},
templates: {
footer: () => {
return [
h(Button, { label: "No", icon: "pi pi-times", onClick: () => dialogRef.close({ buttonType: 'No' }), class: "p-button-text" }),
h(Button, { label: "Yes", icon: "pi pi-check", onClick: () => dialogRef.close({ buttonType: 'Yes' }), autofocus: true})
]
}
},
onClose: (options) => {
const data = options.data;
if (data) {
const buttonType = data.buttonType;
const summary_and_detail = buttonType ? { summary: 'No Product Selected', detail: \`Pressed '\${buttonType}' button\` } : { summary: 'Product Selected', detail: data.name };
toast.add({ severity:'info', ...summary_and_detail, life: 3000 });
}
}
});
}
return { showProducts }
},
components: {
"p-dynamicdialog": primevue.dynamicdialog,
"p-button": primevue.button,
"p-toast": primevue.toast
}
};
const ProductListDemo = {
template: \`<div>
<div class="flex justify-content-end mt-1 mb-3">
<p-button icon="pi pi-external-link" label="Nested Dialog" class="p-button-outlined p-button-success" @click="showInfo"></p-button>
</div>
<p-datatable :value="products" responsive-layout="scroll">
<p-column field="code" header="Code"></p-column>
<p-column field="name" header="Name"></p-column>
<p-column header="Image">
<template #body="slotProps">
<img :src="'demo/images/product/' + slotProps.data.image" @error="(e) => e.target.src = 'https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png'" :alt="slotProps.data.name" class="shadow-2 w-4rem" />
</template>
</p-column>
<p-column field="category" header="Category"></p-column>
<p-column field="quantity" header="Quantity"></p-column>
<p-column style="width:5rem">
<template #body="slotProps">
<p-button type="button" icon="pi pi-plus" class="p-button-text p-button-rounded" @click="selectProduct(slotProps.data)"></p-button>
</template>
</p-column>
</p-datatable>
</div>\`,
inject: ['dialogRef'],
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data.slice(0,5));
},
methods: {
selectProduct(data) {
this.dialogRef.close(data);
},
showInfo() {
this.$dialog.open(InfoDemo, {
props: {
header: 'Information',
modal: true,
dismissableMask: true
},
data: {
totalProducts: this.products ? this.products.length : 0
}
});
}
},
components: {
"p-datatable": primevue.datatable,
"p-column": primevue.column,
"p-button": primevue.button
}
};
const InfoDemo = {
template: \`<div>
<p>There are <strong>{{totalProducts}}</strong> products in total in this list.</p>
<div class="flex justify-content-end">
<p-button type="button" label="Close" @click="closeDialog"></p-button>
</div>
</div>\`,
inject: ['dialogRef'],
data() {
return {
totalProducts: 0
}
},
mounted() {
this.totalProducts = this.dialogRef.data.totalProducts;
},
methods: {
closeDialog() {
this.dialogRef.close();
}
},
components: {
"p-button": primevue.button
}
};
createApp(App)
.use(primevue.config.default)
.use(primevue.dialogservice)
.use(primevue.toastservice)
.mount("#app");
<\\/script>
`
}
},
extFiles: {
'options-api': {
'src/components/ProductListDemo.vue': {
content: `
<template>
<div>
<div class="flex justify-content-end mt-1 mb-3">
<Button icon="pi pi-external-link" label="Nested Dialog" class="p-button-outlined p-button-success" @click="showInfo" />
</div>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="'demo/images/product/' + slotProps.data.image" @error="(e) => e.target.src = 'https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png'" :alt="slotProps.data.name" class="shadow-2 w-4rem" />
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column style="width:5rem">
<template #body="slotProps">
<Button type="button" icon="pi pi-plus" class="p-button-text p-button-rounded" @click="selectProduct(slotProps.data)"></Button>
</template>
</Column>
</DataTable>
</div>
</template>
<script>
import ProductService from '../service/ProductService';
import InfoDemo from './InfoDemo.vue';
export default {
inject: ['dialogRef'],
data() {
return {
products: null
}
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then(data => this.products = data.slice(0,5));
},
methods: {
selectProduct(data) {
this.dialogRef.close(data);
},
showInfo() {
this.$dialog.open(InfoDemo, {
props: {
header: 'Information',
modal: true,
dismissableMask: true
},
data: {
totalProducts: this.products ? this.products.length : 0
}
});
}
}
}
<\\/script>
`
},
'src/components/InfoDemo.vue': {
content: `
<template>
<div>
<p>There are <strong>{{totalProducts}}</strong> products in total in this list.</p>
<div class="flex justify-content-end">
<Button type="button" label="Close" @click="closeDialog"></Button>
</div>
</div>
</template>
<script>
export default {
inject: ['dialogRef'],
data() {
return {
totalProducts: 0
}
},
mounted() {
this.totalProducts = this.dialogRef.data.totalProducts;
},
methods: {
closeDialog() {
this.dialogRef.close();
}
}
}
<\\/script>
`
}
},
'composition-api': {
'src/components/ProductListDemo.vue': {
content: `
<template>
<div>
<div class="flex justify-content-end mt-1 mb-3">
<Button icon="pi pi-external-link" label="Nested Dialog" class="p-button-outlined p-button-success" @click="showInfo" />
</div>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="'demo/images/product/' + slotProps.data.image" @error="(e) => e.target.src = 'https://www.primefaces.org/wp-content/uploads/2020/05/placeholder.png'" :alt="slotProps.data.name" class="shadow-2 w-4rem" />
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column style="width:5rem">
<template #body="slotProps">
<Button type="button" icon="pi pi-plus" class="p-button-text p-button-rounded" @click="selectProduct(slotProps.data)"></Button>
</template>
</Column>
</DataTable>
</div>
</template>
<script>
import { ref, onMounted, inject } from "vue";
import { useDialog } from "primevue/usedialog";
import ProductService from "../service/ProductService";
import InfoDemo from "./InfoDemo.vue";
export default {
setup() {
const dialogRef = inject("dialogRef");
const dialog = useDialog();
const products = ref(null);
const productService = ref(new ProductService());
onMounted(() => {
productService.value
.getProductsSmall()
.then((data) => (products.value = data.slice(0, 5)));
});
const selectProduct = (data) => {
dialogRef.value.close(data);
};
const showInfo = () => {
dialog.open(InfoDemo, {
props: {
header: "Information",
modal: true,
dismissableMask: true,
},
data: {
totalProducts: products.value ? products.value.length : 0,
}
});
};
return { products, selectProduct, showInfo };
}
}
<\\/script>
`
},
'src/components/InfoDemo.vue': {
content: `
<template>
<div>
<p>There are <strong>{{totalProducts}}</strong> products in total in this list.</p>
<div class="flex justify-content-end">
<Button type="button" label="Close" @click="closeDialog"></Button>
</div>
</div>
</template>
<script>
import { ref, onMounted, inject } from "vue";
export default {
setup() {
const totalProducts = ref(0);
const dialogRef = inject("dialogRef");
onMounted(() => {
totalProducts.value = dialogRef.value.data.totalProducts;
});
const closeDialog = () => {
dialogRef.value.close();
};
return { totalProducts, closeDialog };
}
}
<\\/script>
`
}
}
}
};
}
};
</script>

View File

@ -0,0 +1,29 @@
<template>
<div>
<p>
There are <strong>{{ totalProducts }}</strong> products in total in this list.
</p>
<div class="flex justify-content-end">
<Button type="button" label="Close" @click="closeDialog"></Button>
</div>
</div>
</template>
<script>
export default {
inject: ['dialogRef'],
data() {
return {
totalProducts: 0
};
},
mounted() {
this.totalProducts = this.dialogRef.data.totalProducts;
},
methods: {
closeDialog() {
this.dialogRef.close();
}
}
};
</script>

View File

@ -0,0 +1,61 @@
<template>
<div>
<div class="flex justify-content-end mt-1 mb-3">
<Button icon="pi pi-external-link" label="Nested Dialog" class="p-button-outlined p-button-success" @click="showInfo" />
</div>
<DataTable :value="products" responsiveLayout="scroll">
<Column field="code" header="Code"></Column>
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="'demo/images/product/' + slotProps.data.image" :alt="slotProps.data.name" class="shadow-2 w-4rem" />
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="quantity" header="Quantity"></Column>
<Column style="width: 5rem">
<template #body="slotProps">
<Button type="button" icon="pi pi-plus" class="p-button-text p-button-rounded" @click="selectProduct(slotProps.data)"></Button>
</template>
</Column>
</DataTable>
</div>
</template>
<script>
import ProductService from '../../service/ProductService';
import InfoDemo from './InfoDemo.vue';
export default {
inject: ['dialogRef'],
data() {
return {
products: null
};
},
productService: null,
created() {
this.productService = new ProductService();
},
mounted() {
this.productService.getProductsSmall().then((data) => (this.products = data.slice(0, 5)));
},
methods: {
selectProduct(data) {
this.dialogRef.close(data);
},
showInfo() {
this.$dialog.open(InfoDemo, {
props: {
header: 'Information',
modal: true,
dismissableMask: true
},
data: {
totalProducts: this.products ? this.products.length : 0
}
});
}
}
};
</script>

Some files were not shown because too many files have changed in this diff Show More