I have a single Content view that returns objects from a Content restdb database that has a field specifying contenttype = news, facts, faq, etc.
I want the content result view to toggle to the correct phrasing depending on the value of the property. e.g.:
message {
switch (this.contenttype) {
case (news)
{
if ($handsFree) {
if (size(this) > 1)
{
template ("Latest headlines")
{speech ("Latest headlines from #{value(this.identifier)}")}
}
else-if (size(this) == 1)
{template ("")
{speech ("#{value(this.title)}. \n #{value(this.text)}")
}}
}
else {
if (size(this) > 1)
{
template ("Latest headlines")
{speech ("Latest headlines from #{value(this.identifier)}")}
}
else-if (size(this) == 1)
{template ("")
{speech ("#{value(this.title)}.")
}}
}
}
}
switch (this.contenttype) {
case (facts)
{
if ($handsFree) { if (size(this) > 1)
{
template ("I found some facts")
{speech ("Random facts from #{value(this.identifier)}")}
}
else-if (size(this) == 1)
{template ("")
{speech ("#{value(this.title)}. \n #{value(this.text)}")
}}
}
else {
if (size(this) > 1)
{
template ("I found some facts")
{speech ("Random facts from #{value(this.identifier)}")}
}
else-if (size(this) == 1)
{template ("")
{speech ("#{value(this.title)}.")
}}
}
}
}
}
However, this doesn't work. It is bringing back the system default dialog, presumably because something is not working about the switch statement. What are some ways to make this work?
The problem with the code here is the test for the value of (this.contenttype). Contenttype is an array so does not evaluate to a property value. The following code does work by simply looking at the value of the property in the first item in the array:
message {
switch (this.contenttype[0]) {
case (news)
{template ("news")}
case ("facts")
{
if (size(this) > 1) {
template ("I haz found facts")
} else {
template ("#{event(this, 'Result')}")
}
}
default {template ("default is answer")
}
This relies on the server correctly returning all items with the same property as intended by the query.
Related
Hi I want to go to another action by putting a conditional statement in the action output.
What should I do?
For example
action (~~) {
description (Validate items passed from javascript)
collect {
input (~~) {
type (~~)
min (~~) max (~~)
}
}
type(~~~)
output (items){
on-empty(items.item1){ // if items.item1 is empty.
replan { // go to case1Action.
intent {
goal : case1Action
value : ~~~~~
}
}
}else{ // else
replan { // go to case2Action.
intent {
goal : case2Action
value : ~~~~~
}
}
}
}
or I want to select the view according to the output value.(Actually this is the purpose of the question)
output (items){
if(items.item1 == "goFirstCase"){
// First case view
}else{
// Second case view
}
}
I think by "select a different view according to the output value" I presume you mean you want to change what shows on the screen? because a "view" actually is comprised of the dialog, layout, and conversation-drivers.
https://bixbydevelopers.com/dev/docs/dev-guide/developers/building-views.views
For majority of use cases, there's really only one result-view that will be used, and any of the three contents of a view can be changed based on your preferred conditions as the above answer suggests.
within a view you can have the three different components defined with these three blocks: message for dialog, render for layout, and conversation-drivers
using your example,
//in a result-view
message {
if (items.item1 == "firstCase") {
template-macro (firstCase-result-dialog) {//enter params}
}
}
render {
if (size(items) > 1) {
list-of (items) {
where-each (item) {
if (item == "firstCase") {
layout-match (item) {
mode (Summary)
}
// OR use layout-macro
layout-macro (firstCase-result-summary-thumbnail-card) {//enter params}
}
}
}
}
}
similar conditional work can be done on conversation-drivers of course.
In your case, you would not need on-empty in action, but use template-macro-def as briefly explained in https://corp.bixbydevelopers.com/dev/docs/dev-guide/developers/refining-dialog.dialog-macros
// template file one
template-macro-def (id1) {
params {
param (x) {
Type (Items) ....
}
// template file two
template-macro-def (id2) {
// param x is type Items
}
//view file
result-view {
match: Items(this)
// after some checking make sure is single item
// it is possible to use other condition like if (this.sub1 == 2)
if (exists(this.sub1)) {
template-macro (id1) {
param (x) { expression (this) }
}
}
else {
template-macro (id2) {
param (x) { expression (this) }
}
}
The above would be the recommended way to handle different views for same concept in Bixby.
on-empty in action would be used for the purpose of either replan or relax some search condition in order to avoid 0 result. Bixby does not support on-empty(key) {} syntax according to https://corp.bixbydevelopers.com/dev/docs/reference/type/action.output.on-empty and on-empty would only apply in your case if output(items) itself is empty and would not check any sub-property of items.
Another option.
instead to use 'on-empty' block, you can use 'throws - error'
in action model,
output (items) {
throws {
error (case1ActionError) {
on-catch {
replan {
intent {
goal : case1Action
value : ~~~~~
}
}
}
}
error (case2ActionError) {
on-catch {
replan {
intent {
goal : case2Action
value : ~~~~~
}
}
}
}
}
}
And, in js code,,
if (error condition1) {
throw fail.checkedError('case 1 error', 'case1ActionError')
} else if (error condition2) {
throw fail.checkedError('case 2 error', 'case2ActionError')
}
For fail, refer to https://bixbydevelopers.com/dev/docs/reference/JavaScriptAPI/fail#failcheckederrormessage-errorid-errorobj
I am using the Bixby list-of navigation to show multiple tickets and select tickets to show details of that ticket using ordinal-selection-patterns. But if I have only a single ticket and I want to show the detail page of that ticket directly. But I am unable to show.
So, is it possible to call two different actions in the result view.
Result View
result-view {
match: TicketConfirmation(item)
message{
if(exists(item.errorData)){
template("#{value(item.errorData)}")
}
}
render {
if (exists(item.Total) && item.Total >= 1) {
list-of (item) {
navigation-mode {
if ($handsFree) {
read-many {
page-size (6)
page-content (page) {
page-marker {
if(exists(item.customMessage)){
template("")
}
}
underflow-statement (This is the first item.)
overflow-statement (Those are all the items.)
}
}
}
}
where-each (item) {
layout-macro (ticket-summary-card) {
param (single_item) {
expression (item)
}
}
}
}
}
}
}
Layout:
layout-macro-def(ticket-summary-card) {
params {
param (single_item) {
type (TicketConfirmation)
min (Required)
max (One)
}
}
content {
compound-card {
content {
if (exists(single_item.Name)){
paragraph{
value("#{value(single_item.Name)}")
style(Detail_L)
}
}
}
}
}
}
Navigation support:
navigation-support {
match: TicketConfirmation (this)
ordinal-selection-patterns {
pattern ("(first)[v:viv.core.OrdinalSelector]")
pattern ("(first)[v:viv.core.OrdinalSelector] one")
pattern ("that (first)[v:viv.core.OrdinalSelector] one")
}
}
It seems there are two questions here.
I will go with the easy question first:
"is it possible to call two different actions in the result view"?
NO, normally there is only one goal. It is possible that the goal ActionA requires ActionB first and planer handles that with proper training, but developer cannot specify goalA, then goalB like function calls in intent. It is possible to explore the possibility to trigger multiple actions to fulfill a single structure's value by using intent->goal-set. However, a single action to fulfill the value of structure is usually easier and more nature.
Now the more difficult question: "I am using the Bixby list-of navigation to show multiple tickets and select tickets to show details of that ticket using ordinal-selection-patterns. But if I have only a single ticket and I want to show the detail page of that ticket directly. But I am unable to show. "
In runtime-version(7), override with both allow-dialogs-on-detail-pages (true) and no-fallback-dialog-in-views (false)
list-of and where-each should automatically handle the situation you described. You may want have separate render content for ==1 condition. In your code item.Total >= 1, normal practice is do summary in >1 and detail in ==1 condition.
Try to see if there is any difference between HEF and non-HEF, it is unclear from your question whether non-HEF works as desired or not.
"I am unable to show", do you mean you see nothing rendered, or if you see a list view with only 1 item, which requires user to do one more selection step. I will update this answer once learned more.
Updated. I would say just call the detail page directly as the following:
result-view {
match: StructPerson(this)
message: template ("There are #{size(this)} items")
render {
if (size(this)==1) {
// this is the detail view
layout-macro (detail-person) {
param (person) { expression (this) }
}
}
else-if (size(this<1)) {
// this is 0 result view
}
else {
// this is the list view
if ($handsFree) {
// do list navigation here
}
else {
list-of (this) {
where-each (item) {
layout-macro (summary-person) {
param (person) { expression (item)}
}
}
}
}
}
}
}
I want to insert tiny type above the answer set providing a bit of metadata, but can't figure out how to do it. I just want the layout macro content-answer-set-info to say something like "results in reverse chronological order" in Legal or Detail_S. I want it to appear below altbrains workshop and above the first item in the list.
render {
if (size(this) > 1) {
list-of (this) {
has-details (true)
where-each (item) {
layout-macro (content-thumbnail-card) {
param (content) {
expression (item)
}
}
}
}
}
else-if (size(this) == 1) {
layout-match (this) {
mode (Details)
}
}
else {layout-macro (content-zero-results) {}
}
I would recommend wrapping this layout macro in a section and using the section-title (documentation) key to give it the text above the list.
There is an alternative solution that use section -> title but not with list-of
render {
layout {
section {
title {
template ("Voice command Add One")
}
content {
for-each (this) {
as (item) {
title-card {
title-area {
slot2 {
single-line {
text {
value {
template ("Integer: #{value(item.number)}")
}
style (Detail_L)
}
}
}
}
}
}
}
}
}
}
I have a result-view that reads and displays one item at a time:
if (size(this) > 1) {
list-of (this) {
has-details (false)
where-each (item) {
compound-card {
content {
image-card {
aspect-ratio (4:3)
title-area {
halign (Start)
slot1 {
text {
value ("#{value(item.title)}")
style (Title_M)
}
}
}
image-url ("#{value(item.thumbnail)}")
}
paragraph ("#{value(item.partialContent)}")
}
}
}
navigation-mode {
read-one-and-next {
page-content (item) {
underflow-statement ()
next-item-question ()
overflow-statement ()
overflow-question ()
page-marker {
if (isFirstNavPage(item)) {
choose (Random) {
template ("#{value(item.title)}. #{value(item.content)}. Do you want to hear more?")
}
}
else-if (isLastNavPage(item)) {
if (size(item) == 1) {
template ("#{value(item.title)}. You have reach the end of today's #{value(item.topic)}")
}
}
else {
choose (Random) {
template ("#{value(item.title)}. #{value(item.content)}. Do you want to hear more?")
}
}
}
}
}
}
}
}
The question I have is:
how do I get user voice input for "yes/no"?
the flow should be:
- if user said "yes" - reads the next item in the navigation-mode.
- if user said "no" - ends the navigation-mode.
I read something on using
followup
key for getting user yes/no input. But I struggle to find its use here. Should it be use alongside a converation-driver?
The next-page-question key serves as a the prompt for asking the user if they want the next item in the list. The user's "yes" or "no" response is handled by navigation mode without any additional coding from you.
What are some good examples of different ways to handle zero result search answer sets in result views?
Here's what I have right now. I assume I want to do size(this) < 1 but before I plunge ahead I want some ideas about what to do. For example, should I just say "search again" or should I try to recommend something to do?
render {
if (size(this) > 1) {
list-of (this) {
//default-sort-order {
// sorting(this.title)
// }
has-details (true)
where-each (item) {
layout-macro (content-thumbnail-card) {
param (content) {
expression (item)
}
}
}
}
} else-if (size(this) == 1) {
layout-match (this) {
mode (Details)
}
}
}
There is a NoResult dialog that will automatically activate for this condition:
https://bixbydevelopers.com/dev/docs/reference/ref-topics/dialog-modes.dialog-events#no-result-event
You can also place a conditional in your result view. For example:
result-view {
match: SomeConcept(this)
message {
if (size(this) == 0) {
template (No results)
}
}
render {
layout {
section {
content {
// No Result
if (size(this)== 0) {
paragraph(Sorry, I didn't find anything)
}
}
}
}
}
}