Hi - We are currently working on building a chatbot. As part of that we tried to mimic the traditional chat UI by leveraging Appian components. However, we are facing an issue displaying the latest message entered by the user on a card layout. A scroll bar appears in this scenario and we need to manually scroll it. Also, Auto height on card layout doesn't work as chat window getting bigger. Any alternative approach or a way that we can take care of auto vertical scrolling on a component?
TIA
Discussion posts and replies are publicly visible
Hi Riyaz Shaik
Is it possible to share the code snippet to better understand the problem. Generally speaking, the card layout needs to be refreshed on each event(new message etc.), it can be achieved by using refreshVariable.
I also tried to implement chat in appian and face the same issue , however i resolved it and brought recent messages on top , means new messages will come at top and older messages will get at bottom like stack data structure
Hi Abhay - Good to hear from you. I’ll give a try. Thanks
Hi Aman - thanks for your response. Could you able to share the code snippet for reference?
Hi Riyaz,
Could you please try this code . You may get some help . You can play around the UIs but lets see if this logic helps you
Here is the URL to try it
tlpf.appianportals.com/chatapp
a!localVariables( local!data:{}, local!msg, local!showAll:false(), a!formLayout( skipAutoFocus: false(), label: "Welcome", contents: { a!buttonLayout( primaryButtons: a!buttonWidget( label: if( local!showAll=false(), "Show All","Latest"), value: if( local!showAll=false(), true(),false()), saveInto: local!showAll ) ), if( local!showAll, a!forEach( items: local!data, expression: a!columnsLayout( columns: { a!columnLayout( contents: { a!textField( value: fv!item.msg, readOnly: true(), showWhen: if( loggedInUser()=fv!item.msgBy, true(), false() ) ) },
), a!columnLayout( contents: { a!textField( align: "RIGHT", value: fv!item.msg, readOnly: true(), showWhen: if( loggedInUser()=fv!item.msgBy, false(), true() ) ) } ) } ) ), {a!forEach( items: reverse(todatasubset(reverse(local!data),a!pagingInfo(1,5)).data), expression: a!columnsLayout( columns: { a!columnLayout( contents: { a!textField( value: fv!item.msg, readOnly: true(), showWhen: if( loggedInUser()=fv!item.msgBy, true(), false() ) ) },
), a!columnLayout( contents: { a!textField( align: "RIGHT", value: fv!item.msg, readOnly: true(), showWhen: if( loggedInUser()=fv!item.msgBy, false(), true() ) ) } ) } ) ), a!textField( value: local!msg, saveInto: { local!msg, }, ), a!buttonLayout( primaryButtons: { a!buttonWidget( label: "submit", saveInto: { a!save( local!data, append( local!data, 'type!{urn:com:appian:types:PD}PD_chatDetails'( id: count(local!data)+1 , msg: local!msg, msgBy: loggedInUser(), msgDate: now() ) ) ), a!save(local!msg,null)}, size: "SMALL" ) } )}) } ))
{ a!localVariables( local!recordData: a!queryRecordType( recordType: 'recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment', filters: { a!queryFilter( field: 'recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{7839be35-1eac-4fea-bcff-9f65422c281b}caseId', operator: "=", value: ri!caseId ) }, pagingInfo: a!pagingInfo(1, 1), fetchTotalCount: true ), local!totalCount: local!recordData.totalCount, local!batchSize: 4, local!startIndex: if( local!totalCount <= local!batchSize, 1, local!totalCount - if( mod(local!totalCount, local!batchSize) = 0, local!batchSize, mod(local!totalCount, local!batchSize) ) + 1 ), local!pagingInfo: a!pagingInfo( startIndex: local!startIndex, batchSize: local!batchSize ), local!record: a!queryRecordType( recordType: 'recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment', filters: { a!queryFilter( field: 'recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{7839be35-1eac-4fea-bcff-9f65422c281b}caseId', operator: "=", value: ri!caseId ) }, pagingInfo: local!pagingInfo ), local!comments: local!record.data, local!caseOwner: a!queryRecordType( recordType: 'recordType!{28dade06-19f7-4add-9a25-12b5a7c5c5a2}AHP Case', filters: { a!queryFilter( field: 'recordType!{28dade06-19f7-4add-9a25-12b5a7c5c5a2}AHP Case.fields.{37f7ef43-b1ae-4978-9c0c-5cd22284e7cf}id', operator: "=", value: ri!caseId ) }, pagingInfo: a!pagingInfo(startIndex: 1, batchSize: 1000) ).data['recordType!{28dade06-19f7-4add-9a25-12b5a7c5c5a2}AHP Case.fields.{a2eae269-4b53-4a29-8e22-4d3087e084ef}caseOwner'], local!addNew: true(), local!newComment, { a!cardLayout( contents: a!sectionLayout( label: "Comments", labelIcon: "comments", divider: "ABOVE", marginAbove: "STANDARD", isCollapsible: true(), contents: a!columnsLayout( columns: { a!columnLayout( contents: { rule!AHP_paginationSection( pagingInfo: local!pagingInfo, totalCount: local!totalCount ), a!cardLayout( showBorder: false(), showShadow: false(), padding: "NONE", contents: { /*Comments in conversation view*/ a!forEach( items: local!comments, expression: a!localVariables( local!fullName: user( username: fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{46704656-32a1-4ec6-b011-9c98222e9b3e}createdBy'], property: "firstName" ) & " " & user( username: fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{46704656-32a1-4ec6-b011-9c98222e9b3e}createdBy'], property: "lastName" ), local!showProfilePhoto: a!isNotNullOrEmpty( getprofilepictureforuser( fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{46704656-32a1-4ec6-b011-9c98222e9b3e}createdBy'] ) ), local!isLoggedInUser: loggedInUser() = fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{46704656-32a1-4ec6-b011-9c98222e9b3e}createdBy'], local!isCaseOwner: local!caseOwner = fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{46704656-32a1-4ec6-b011-9c98222e9b3e}createdBy'], { a!columnsLayout( columns: { a!columnLayout( width: "EXTRA_NARROW", showWhen: local!isLoggedInUser ), a!columnLayout( contents: { a!cardLayout( contents: { a!sectionLayout( contents: { a!sideBySideLayout( items: { /*a!sideBySideItem(showWhen: local!isLoggedInUser),*/ a!sideBySideItem( item: a!stampField( labelPosition: "COLLAPSED", text: initials(local!fullName), backgroundColor: "SECONDARY", size: "TINY", align: if(local!isLoggedInUser, "END", "START") ), width: "MINIMIZE", showWhen: not(local!showProfilePhoto) ), a!sideBySideItem( item: a!imageField( labelPosition: "COLLAPSED", images: a!userImage( user: fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{46704656-32a1-4ec6-b011-9c98222e9b3e}createdBy'], altText: local!fullName, caption: local!fullName ), size: "TINY", style: "AVATAR", align: if(local!isLoggedInUser, "END", "START") ), width: "MINIMIZE", showWhen: local!showProfilePhoto ), a!sideBySideItem( item: a!richTextDisplayField( labelPosition: "COLLAPSED", value: { a!richTextItem( text: concat( local!fullName, if( local!isCaseOwner, " (Case Owner)", "" ) ), /*link: a!userRecordLink(),*/ linkStyle: "STANDALONE", style: "STRONG", /*color: "ACCENT"*/ ), char(10), a!richTextItem( /*text: if(*/ /*tointeger(todatetime(now()) - fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{7e212791-306c-4327-8817-dbbe1e67e9ab}createdOn']) < 1,*/ /*todatetime(todatetime(now()) - fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{7e212791-306c-4327-8817-dbbe1e67e9ab}createdOn']),*/ /*fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{7e212791-306c-4327-8817-dbbe1e67e9ab}createdOn']*/ /*),*/ text: fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{7e212791-306c-4327-8817-dbbe1e67e9ab}createdOn'], /*color: "#ffffff",*/ style: "EMPHASIS" ) } ), width: "MINIMIZE" ) }, alignVertical: "MIDDLE" ) } ), a!textField( labelPosition: "COLLAPSED", value: fv!item['recordType!{59505fbe-4a2d-41cf-b01c-b6b44dce0683}AHP Comment.fields.{17d45582-c2bb-4d6d-8e41-508da99fefae}comment'], readOnly: true, /*align: if(*/ /*local!isLoggedInUser,*/ /*"RIGHT",*/ /*"LEFT"*/ /*)*/ ) }, style: if( local!isLoggedInUser, "#3DA9BE", "#1B478F" ), shape: "ROUNDED", padding: "EVEN_LESS", marginBelow: "STANDARD", showShadow: true ) } ), a!columnLayout( width: "EXTRA_NARROW", showWhen: not(local!isLoggedInUser) ) } ) } ) ) }, height: "AUTO" ), a!sideBySideLayout( items: { /*Comment Box*/ a!sideBySideItem( item: a!textField( placeholder: "Type your comment here...", value: local!newComment, saveInto: local!newComment, refreshAfter: "KEYPRESS", showWhen: local!addNew ) ), /*Save comment button*/ a!sideBySideItem( item: a!richTextDisplayField( value: { a!richTextItem( text: a!richTextIcon(icon: "paper-plane"), link: if( a!isNullOrEmpty(local!newComment), {}, a!startProcessLink( label: "Save", processModel: cons!AHP_PM_CREATE_COMMENT, processParameters: { comment: local!newComment, caseId: ri!caseId } ) ), linkStyle: "STANDALONE", size: "MEDIUM", style: "STRONG" ) }, showWhen: local!addNew, align: "RIGHT" ), width: "MINIMIZE" ) }, alignVertical: "MIDDLE" ) } ) } ) ), shape: "ROUNDED", marginBelow: "STANDARD", showBorder: true(), showShadow: true(), style: "NONE" ) } ) } /* Pagination section code below */ a!sideBySideLayout( items: { a!sideBySideItem(), a!sideBySideItem( item: a!richTextDisplayField( labelPosition: "COLLAPSED", value: { a!richTextIcon( icon: "angle-double-left", link: a!dynamicLink( value: 1, saveInto: ri!pagingInfo.startIndex, showWhen: tointeger(ri!pagingInfo.startIndex) <> 1 ), linkStyle: "STANDALONE", color: if( tointeger(ri!pagingInfo.startIndex) = 1, "SECONDARY", "ACCENT" ), size: "MEDIUM_PLUS" ), a!richTextIcon( icon: "angle-left", link: a!dynamicLink( value: tointeger(ri!pagingInfo.startIndex) - tointeger(ri!pagingInfo.batchSize), saveInto: ri!pagingInfo.startIndex, showWhen: tointeger(ri!pagingInfo.startIndex) <> 1 ), linkStyle: "STANDALONE", color: if( tointeger(ri!pagingInfo.startIndex) = 1, "SECONDARY", "ACCENT" ), size: "MEDIUM_PLUS" ) }, showWhen: or(ri!totalCount > 0), align: "RIGHT" ), width: "MINIMIZE" ), a!sideBySideItem( item: a!richTextDisplayField( labelPosition: "COLLAPSED", value: { a!richTextItem( text: concat( ri!pagingInfo.startIndex, " - ", if( ri!pagingInfo.startIndex + ri!pagingInfo.batchSize > ri!totalCount, ri!totalCount, ri!pagingInfo.startIndex + ri!pagingInfo.batchSize - 1 ) ), style: "STRONG" ), a!richTextItem(text: concat(" of ", ri!totalCount)), }, showWhen: or(ri!totalCount > 0), align: "RIGHT" ), width: "MINIMIZE" ), a!sideBySideItem( item: a!richTextDisplayField( labelPosition: "COLLAPSED", value: { a!richTextIcon( icon: "angle-right", link: a!dynamicLink( value: tointeger(ri!pagingInfo.startIndex) + tointeger(ri!pagingInfo.batchSize), saveInto: ri!pagingInfo.startIndex, showWhen: ( tointeger(ri!pagingInfo.startIndex) + tointeger(ri!pagingInfo.batchSize) ) <= tointeger(ri!totalCount) ), linkStyle: "STANDALONE", color: if( ( tointeger(ri!pagingInfo.startIndex) + tointeger(ri!pagingInfo.batchSize) ) <= tointeger(ri!totalCount), "ACCENT", "SECONDARY" ), size: "MEDIUM_PLUS" ), a!richTextIcon( icon: "angle-double-right", link: a!dynamicLink( value: if( mod( tointeger(ri!totalCount), tointeger(ri!pagingInfo.batchSize) ) > 0, tointeger(ri!totalCount) - mod( tointeger(ri!totalCount), tointeger(ri!pagingInfo.batchSize) ) + 1, tointeger(ri!totalCount) - tointeger(ri!pagingInfo.batchSize) + 1 ), saveInto: ri!pagingInfo.startIndex, showWhen: ( tointeger(ri!pagingInfo.startIndex) + tointeger(ri!pagingInfo.batchSize) ) <= tointeger(ri!totalCount) ), linkStyle: "STANDALONE", color: if( ( tointeger(ri!pagingInfo.startIndex) + tointeger(ri!pagingInfo.batchSize) ) <= tointeger(ri!totalCount), "ACCENT", "SECONDARY" ), size: "MEDIUM_PLUS" ) }, showWhen: or(ri!totalCount > 0), align: "RIGHT" ), width: "MINIMIZE" ), }, alignVertical: "MIDDLE", showWhen: and( or(ri!totalCount > 0), not( or(ri!totalCount <= ri!pagingInfo.batchSize) ) ), spacing: "NONE" )