A collection of code snips using Lucidworks App Studio – a modular code framework for developing bespoke, data-anywhere search and discovery web applications.
Contents
- Angular Statements
- ng-class
- ng-if
- Comments Form
- Add icon to POST button
- Change text of POST button
- Facets / Filters
- Facet naming
- Images
- Images missing from app deployed to server
- Modal Dialog
- Two-color dialog header
- Modal timeout
- Search Result
- Currency fields
Angular Statements
ng-class
Add a class called “displayresult” to a tag if the search result’s foo
field is not empty.
<search:result ng-class="{'displayresult': result.fields.foo.val[0] !== undefined}">
<div> ... stuff ... </div>
</search:result>
Add a class called “clear-border” to layout block if a “more” button click condition in the controller has been met.
<layout:block ng-class="{'clear-border': moreon}">
<div> ... stuff ... </div>
</layout:block>
ng-if
Show image if the result’s hyperlink
field is not empty.
<img ng-if="(result.fields.hyperlink.val[0] !== undefined)">
ng-src="{{result|field:'image'|actual}}?v={{$root.version}}"
title="{{result|field:'title'|display}}" />
Show image if search result’s image
field is not empty and environment
field contains the string “Tree”
<span ng-if="(result.fields.image.val[0] === undefined && result.fields.environment.val[0].indexOf('Tree') > -1)">
<img class="static" ng-src="{{$root.contextPath}}assets/icons/tree.png?v={{$root.version}}"/>
</span>
Show block if a whole bunch of conditions are met
<layout:block ng-if="(result.fields.image.val[0] !== undefined && result.fields.tab.val[0].indexOf('Apps') < 0
|| (result.fields.tab.val[0].indexOf('Reports') > -1 && result.fields.environment.val[0].indexOf('Hyperspace') > -1)
|| (result.fields.tab.val[0].indexOf('Reports') > -1 && result.fields.environment.val[0].indexOf('InfoView') > -1)
|| (result.fields.tab.val[0].indexOf('Reports') > -1 && result.fields.environment.val[0].indexOf('Insights') > -1)
|| (result.fields.tab.val[0].indexOf('Reports') > -1 && result.fields.environment.val[0].indexOf('Logic') > -1)
|| (result.fields.tab.val[0].indexOf('Reports') > -1 && result.fields.environment.val[0].indexOf('Vantage') > -1)
)
&& !((result.fields.tab.val[0].indexOf('Reports') > -1 && result.fields.environment.val[0].indexOf('Tableau') > -1))
&& result.fields._lw_data_source_s.val[0].indexOf('Galleries') === -1"
>
<div> ... stuff ... </div>
</layout:block>
Comments Form
Add icon to POST button
Add a styling or class to the <social:comment-form>
tag that refers to the form like myCommentForm
or myButton
.
<social:comment-form
target="result.id"
styling="myCommentForm"
class="myButton"
></social:comment-form>
Then in CSS, specify the button’s background, width and height as needed.
.tk-stl-myCommentForm {
.tk-stl-comment-form {
margin: 0;
.tk-stl-button {
background: lighten(#1571bc, 10%);
margin: 0.427rem 0 0 0;
padding: 0 0.8em;
height: 1.757rem;
font-weight: bold;
text-indent: 1.5rem;
line-height: 2.15;
width: 4.5rem;
}
.tk-stl-button::after {
content: url(../../assets/search/icon_post_14.svg);
text-indent: -0.2rem;
display: block;
margin-top: -1.4rem;
width: 1.125rem;
}
}
}
Change text of POST button
Add a class to the <social:comment-form>
tag that collapses the original text line and adds the new text.
.myButton {
.tk-stl-button.tk-stl-button-small {
text-indent: -9999px;
line-height: 0;
}
.tk-stl-button.tk-stl-button-small::after {
content: "New button text";
text-indent: 0;
display: block;
line-height: initial;
}
}
Facets / Filters
Facet naming
Option 1 – add the facet name aliases in the markup through the facet-name parameter
in a <search:facet>
tag.
<search:facet-list
platform="platform"
query="query"
response="response"
styling="facet-list facet-list-wrappedheader"
show-empty="false"
>
<search:facet
facet-name="topics_hier=Topics"
show="5"
show-more="15"
>
<facet:hierarchical
facet-name="topics_hier"
platform="p_hierarchical"
query="query"
select="multiselect"
>
</facet:hierarchical>
</search:facet>
<search:facet
facet-name="environment=Environment"
collapsible="true"
max-characters="40"
select="multiselect"
show="5"
show-more="15"
></search:facet>
</search:facet-list>
Option 2 – add the facet name aliases in the markup through the facet-name
parameter in a <search:facet-list>
tag.
<search:facet-list
platform="platform"
query="query"
response="response"
styling="facet-list facet-list-wrappedheader"
show-empty="false"
facet-name="environment=Environment, product_type=Product, entity=Business Entity">
<search:facet
collapsible="true"
max-characters="40"
select="multiselect"
show="5"
show-more="15"
></search:facet>
</search:facet-list>
Option 3: add facet name aliases by injecting the TranslationService
library into a controller along with a line for each facet field you want to give an alias to. Here’s an example using the high-level controller and function in /scripts/controllers/main.js
:
angular.module('twigkitLightApp')
.controller('MainCtrl', ['$rootScope', '$scope', '$stateParams', '$location', 'ModalService', '$twigkit', '$window', '$timeout', 'TranslationService',
function ($rootScope, $scope, $stateParams, $location, ModalService, $twigkit, $window, $timeout, TranslationService) {
// Transform Facet Name Aliases
TranslationService.put('topics_hier', 'Topics');
TranslationService.put('training_audience', 'Training Audience');
}]);
Continue to use the original field name in the markup and the translation will appear when the page is rendered, as the facet names no longer require the ad-hoc aliasing in the markup.
<search:facet-list
platform="platform"
query="query"
response="response"
styling="facet-list facet-list-wrappedheader"
show-empty="false"
>
<search:facet
facet-name="topics_hier">
<facet:hierarchical
facet-name="topics_hier"
platform="p_hierarchical"
query="query"
select="multiselect"
></facet:hierarchical>
</search:facet>
<search:facet
facet-name="environment"
collapsible="true"
max-characters="40"
select="multiselect"
show="5"
show-more="99"
></search:facet>
</search:facet-list>
Images
Images missing from app deployed to server
Sometimes image code and tags don’t work when an app is deployed to the company web server, even though everything works fine when viewed in the local desktop development environment running Jetty. Here are some of the basics to check when this happens. In main.js, set the context path to /
. This will interpret to https://servername:8080/appname
. The image service eventually needs to reach this path.
// Set the context path for assets and pages
$rootScope.contextPath = $twigkit.getContextPath('/');
Then in the <media:image>
tag on the HTML page, set the image-service-url
parameter value the context path in main.js. The image-service-url
parameter in the following example points to both the context path and a custom image service in /src/main/resources/conf/services/images/tableau
which calls a Tableau server API to retrieve thumbnails:
<!-- has hyperlink and image from Tableau -->
<media:image
ng-if="(result.fields.image.val[0] !== undefined && result.fields._lw_data_source_s.val[0].indexOf('Tableau') > -1)"
src="{{tableauImageUrl(result, $root.version) | trusted}}"
image-service-url="{{$root.contextPath}}twigkit/services/images/tableau/"
use-headers="true"
></media:image>
Set the context path in Tomcat. If the images DO display when deployed as root.war to Tomcat, then check Reverse Proxy settings.
add <Context path=”” docBase=”myhiway” debug=”0″ reloadable=”true”></Context>
to server.xml?
Modal Dialog
Two-color dialog header
This two-color modal header solution differentiates between a static prefix phrase like Gallery Item and a mutable string like Value Oriented Architecture.
In the <widget:modal>
tag on the HTML page/view, enter the desired full text heading as plain text or variable to the title attribute, along with a class name through the modal-classes attribute.
<widget:modal id="viewdetails{{result.id}}" title="Value Oriented Architecture" modal-classes="psjh-gallery-modal">
<layout:include file="views/modals/viewdetails.html" value="{{result.id}}"></layout:include>
</widget:modal>
Add this modal class name to LESS/SASS with a reference to the framework’s default header style which contains a :before pseudo-element that manages the desired phrase prefix. Adjust colors as desired.
.psjh-gallery-modal .tk-stl-modal-header {
color: #000 !important;
:before {
content:"Gallery Item - ";
color: #f1933c;
}
}
The result should be a two-color modal dialog heading that came from a single attribute.
Modal timeout
When a modal widget built on the App Studio ModalService service works on only on a few desktops, a failure in event timing may be the cause.
<widget:modal style="z-index: 1000;" id="TimeoutModal">
<div id="timeoutContainer">
...
</div>
</widget:modal>
Try wrapping calls from the ModalService.show function in custom.js with a timeout function.
// Timeout Warning - show modal dialog
$scope.$on('IdleStart', function () {
$scope.showModal('TimeoutModal');
});
// Timeout Warning - set modal services (note: needs timeout to work in all browsers)
$scope.showModal = function (id) {
$timeout(function () {
ModalService.show(id);
}, 0);
};
Search Results
Currency fields
Add the currency field to Solr’s managed-schema.xml as either a string or an integer.
<field indexed="true" multiValued="false" name="cost_str" required="false" stored="true" type="string"/>
<field indexed="true" multiValued="false" name="cost_int" required="false" stored="true" type="ints"/>
Then in App Studio, add either field to a <search:field>
tag with the number-format
parameter.
<!-- Products, Parts, Accessories, and Supplies -->
<layout:block styling="psjh-result-table"
ng-if="((result.fields._lw_data_source_s.val[0].indexOf('Documents')) === 0)">
<search:field label="Product ID:" name="id" styling="meta label-inline"></search:field>
<search:field label="CostA:" name="cost_str" number-format="$#,###.##" styling="meta label-inline"></search:field>
<search:field label="CostB:" name="cost_int" number-format="$#,###.##" styling="meta label-inline"></search:field>
</layout:block>