<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Calcapp</title>
    <description>Forget error-prone Excel calculators and build apps instead. Imagine a cloud-based app designer enabling you to create apps without having to do any programming.
</description>
    <link>https://www.calcapp.net/</link>
    <atom:link href="https://www.calcapp.net/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 10 Jul 2026 22:11:33 +0000</pubDate>
    <lastBuildDate>Fri, 10 Jul 2026 22:11:33 +0000</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>
    
      <item>
        <title>Tip: Role-driven drop-down filtering</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Control what users see in drop-downs based on their role or company, ensuring
  each person only accesses relevant options for their responsibilities.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;When multiple departments or external partners use the same app, you don’t want
everyone seeing every option in your drop-downs. A marketing manager shouldn’t
see engineering project codes, and contractors shouldn’t access internal
employee resources. Smart drop-down filtering based on user identity solves this
automatically.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;/blog/2019/04/12/private-apps.html&quot;&gt;private apps&lt;/a&gt;, drop-down options can adapt to who’s signed in,
showing only what’s relevant to their role or organization. This goes beyond
filtering based on user selections (&lt;a href=&quot;/blog/2026/04/15/drop-downs-filter-optional.html&quot;&gt;covered here&lt;/a&gt;)
— the app knows who the user is and adjusts accordingly.&lt;/p&gt;

&lt;h2 id=&quot;filtering-by-role&quot;&gt;Filtering by role&lt;/h2&gt;

&lt;p&gt;User roles are typically managed through &lt;a href=&quot;/blog/2019/04/12/private-apps.html&quot;&gt;tags&lt;/a&gt; assigned to each
person when they’re granted app access. For our project management example,
let’s say users have either &lt;em&gt;Employee&lt;/em&gt; or &lt;em&gt;Contractor&lt;/em&gt; tags.&lt;/p&gt;

&lt;p&gt;Consider this project resource table, stored in a &lt;a href=&quot;/blog/2025/10/15/first-screen.html#hiding-your-back-end&quot;&gt;hidden&lt;/a&gt;
form screen named &lt;em&gt;ProjectResources&lt;/em&gt; and created using our
&lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data editor&lt;/a&gt;:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;ResourceName&lt;/th&gt;
      &lt;th&gt;Category&lt;/th&gt;
      &lt;th&gt;AccessRole&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;

  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Customer Database Access&lt;/td&gt;
      &lt;td&gt;Data Systems&lt;/td&gt;
      &lt;td&gt;Employee&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Internal Wiki&lt;/td&gt;
      &lt;td&gt;Documentation&lt;/td&gt;
      &lt;td&gt;Employee&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Project Asset Library&lt;/td&gt;
      &lt;td&gt;Shared Resources&lt;/td&gt;
      &lt;td&gt;Contractor&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Contractor Guidelines&lt;/td&gt;
      &lt;td&gt;Documentation&lt;/td&gt;
      &lt;td&gt;Contractor&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Shared Calendar&lt;/td&gt;
      &lt;td&gt;Scheduling&lt;/td&gt;
      &lt;td&gt;Employee&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Public Templates&lt;/td&gt;
      &lt;td&gt;Shared Resources&lt;/td&gt;
      &lt;td&gt;Contractor&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;To display only the resources available to the signed-in user, associate this
formula with the &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(ProjectResources!ResourceName, &lt;span class=&quot;function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt;(ProjectResources!AccessRole))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(ProjectResources!ResourceName; &lt;span class=&quot;function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt;(ProjectResources!AccessRole))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The FILTER function returns a subset of the &lt;em&gt;ResourceName&lt;/em&gt; column based on a
logical test. For each row, USERHASTAG checks if the signed-in user has the tag
specified in the &lt;em&gt;AccessRole&lt;/em&gt; column. When TRUE, that resource name appears in
the drop-down. When FALSE, it’s excluded.&lt;/p&gt;

&lt;p&gt;Employees see “Customer Database Access,” “Internal Wiki” and “Shared Calendar,”
while contractors see “Project Asset Library,” “Contractor Guidelines” and
“Public Templates.”&lt;/p&gt;

&lt;h2 id=&quot;filtering-by-company&quot;&gt;Filtering by company&lt;/h2&gt;

&lt;p&gt;If you don’t use role tags, company affiliation works just as well. Many
organizations identify users by their email domain, automatically determining
which company they represent.&lt;/p&gt;

&lt;p&gt;Here’s a client project table stored in a form screen named &lt;em&gt;ClientProjects&lt;/em&gt;:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;ProjectName&lt;/th&gt;
      &lt;th&gt;ProjectType&lt;/th&gt;
      &lt;th&gt;ClientDomain&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;

  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Website Redesign Q1&lt;/td&gt;
      &lt;td&gt;Design&lt;/td&gt;
      &lt;td&gt;acmecorp.com&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Mobile App Development&lt;/td&gt;
      &lt;td&gt;Development&lt;/td&gt;
      &lt;td&gt;acmecorp.com&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Brand Guidelines Update&lt;/td&gt;
      &lt;td&gt;Strategy&lt;/td&gt;
      &lt;td&gt;techstartup.io&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;E-commerce Platform&lt;/td&gt;
      &lt;td&gt;Development&lt;/td&gt;
      &lt;td&gt;techstartup.io&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Marketing Automation&lt;/td&gt;
      &lt;td&gt;Strategy&lt;/td&gt;
      &lt;td&gt;globalmfg.com&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Supply Chain Dashboard&lt;/td&gt;
      &lt;td&gt;Analytics&lt;/td&gt;
      &lt;td&gt;globalmfg.com&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;To show only projects relevant to the user’s company, use this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(ClientProjects!ProjectName, &lt;span class=&quot;function&quot; name=&quot;ENDSWITH&quot;&gt;ENDSWITH&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;UserEmailAddress&quot;&gt;UserEmailAddress&lt;/span&gt;, &quot;@&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ClientProjects!ClientDomain))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(ClientProjects!ProjectName; &lt;span class=&quot;function&quot; name=&quot;ENDSWITH&quot;&gt;ENDSWITH&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;UserEmailAddress&quot;&gt;UserEmailAddress&lt;/span&gt;; &quot;@&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ClientProjects!ClientDomain))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This works similarly to role-based filtering. The ENDSWITH function checks if
the user’s email address ends with “@” plus the domain from the &lt;em&gt;ClientDomain&lt;/em&gt;
column. Users from acmecorp.com see only their website and mobile projects,
while techstartup.io users see their brand and e-commerce work.&lt;/p&gt;

&lt;p&gt;This approach eliminates the need to manually assign company tags — the system
determines affiliation automatically from email addresses, reducing
administrative overhead while maintaining strict access control.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This technique requires named values, which are not available in our
Starter plans.&lt;/p&gt;

</description>
        <pubDate>Fri, 10 Jul 2026 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2026/07/10/drop-downs-roles.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2026/07/10/drop-downs-roles.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Filter drop-downs with optional criteria</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Filter drop-downs using criteria that users can set as TRUE, FALSE or
  &quot;don&apos;t care,&quot; making large data tables manageable.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Filter%20drop-downs%20with%20optional%20criteria
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Drop-downs displaying columns from large data tables can be
overwhelming. Filtering helps users find what they need by showing
only relevant values.&lt;/p&gt;

&lt;p&gt;A separate tip covers &lt;a href=&quot;/blog/2025/12/14/drop-downs-filter-text-field.html&quot;&gt;filtering by text&lt;/a&gt;. This
tip focuses on filtering based on logical columns (TRUE and FALSE values) in
your data table.&lt;/p&gt;

&lt;p&gt;Users need three options for each filter criterion — TRUE, FALSE and
“I don’t care.” Without that third option, filtering becomes too
restrictive. For example, if users want to see all products that are
on sale, they shouldn’t need to specify whether those products are
discontinued or featured.&lt;/p&gt;

&lt;p&gt;We’ll explore this with two example apps. The first demonstrates the concept
using switch fields, while the second shows the practical solution using
indeterminate drop-downs.&lt;/p&gt;

&lt;h2 id=&quot;the-underlying-data-table&quot;&gt;The underlying data table&lt;/h2&gt;

&lt;p&gt;The next form screen, &lt;em&gt;Products&lt;/em&gt;, contains this data table (edited using Calcapp
Creator’s built-in &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data editor&lt;/a&gt;):&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Product Name&lt;/th&gt;
      &lt;th&gt;On Sale&lt;/th&gt;
      &lt;th&gt;Discontinued&lt;/th&gt;
      &lt;th&gt;Featured&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Instant Pot&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Smart Speaker&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Wireless Earbuds&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Electric Mixer&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Smartwatch&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Bluetooth Speaker&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Gaming Console&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Digital Camera&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;LED TV&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Game Controller&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Fitness Tracker&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Home Appliance&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Air Purifier&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Food Processor&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Electric Kettle&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;understanding-the-concept-switch-fields&quot;&gt;Understanding the concept: Switch fields&lt;/h2&gt;

&lt;p&gt;Here’s the first example app using switch fields:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 390px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=c6ie5b&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;The text drop-down field at the bottom contains a list of products, which may be
on sale, discontinued or featured. Check the &lt;strong&gt;Filter&lt;/strong&gt; switch field to enable
filtering with three switch fields.&lt;/p&gt;

&lt;p&gt;This simpler approach helps explain the filtering concept, even though we’ll
need to enhance it to be truly useful.&lt;/p&gt;

&lt;p&gt;With switch fields, users can only specify TRUE or FALSE for each criterion —
there’s no “I don’t care” option yet. Initially, all three switch fields are
off, meaning only products that are &lt;strong&gt;not&lt;/strong&gt; on sale, &lt;strong&gt;not&lt;/strong&gt; discontinued and
&lt;strong&gt;not&lt;/strong&gt; featured appear in the drop-down.&lt;/p&gt;

&lt;p&gt;If you enable both the &lt;strong&gt;Discontinued&lt;/strong&gt; and &lt;strong&gt;Featured&lt;/strong&gt; switch fields, no
products remain. That’s consistent with the table — no rows have both values
set to TRUE.&lt;/p&gt;

&lt;p&gt;To achieve this, assign this formula to the &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; property of the products drop-down:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Filter, FilteredProducts, Products!ProductName)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Filter; FilteredProducts; Products!ProductName)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If the &lt;strong&gt;Filter&lt;/strong&gt; switch field is on, the drop-down comes from the
&lt;em&gt;FilteredProducts&lt;/em&gt; named value. Otherwise, it contains all product names from
the &lt;em&gt;Products&lt;/em&gt; form screen (representing the data table).&lt;/p&gt;

&lt;p&gt;(A &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named value&lt;/a&gt; is normally hidden and can store any formula
result. They help shorten formulas and improve readability.)&lt;/p&gt;

&lt;p&gt;Here, we use a named value to represent the filtered values of the drop-down
field. Here’s the formula for &lt;em&gt;FilteredProducts&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Products!ProductName, (Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Discontinued &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Discontinued) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Featured &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Featured))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Products!ProductName; (Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Discontinued &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Discontinued) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Featured &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Featured))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; takes an &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;array&lt;/a&gt; and returns a version of it,
potentially without certain elements (thereby filtering them out). The first
parameter is the array to filter and the second is a logical array of the same
size as the first array, where TRUE means the element at the same position in
the first array is kept and FALSE means it is removed.&lt;/p&gt;

&lt;p&gt;Let’s imagine that the second parameter only consists of this formula fragment:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It references the &lt;em&gt;OnSale&lt;/em&gt; named value of the &lt;em&gt;Products&lt;/em&gt; form screen, thereby
representing whether a product is on sale in the data table. It uses the
&lt;span class=&quot;link binaryOperator&quot; name=&quot;=&quot;&gt;=&lt;/span&gt; operator with the &lt;em&gt;OnSale&lt;/em&gt; switch field of the first screen.&lt;/p&gt;

&lt;p&gt;What does that do? It produces a logical array where the only elements that are
TRUE are the ones where the &lt;em&gt;OnSale&lt;/em&gt; switch field has a value that is equal to
the &lt;em&gt;OnSale&lt;/em&gt; column of the data table. If FILTER was given that logical array
as its second parameter, it would produce a filtered version of the product
names containing only those products that were or were not on sale, depending
on the value of the &lt;em&gt;OnSale&lt;/em&gt; switch field.&lt;/p&gt;

&lt;p&gt;Of course, this is the complete second parameter we give to FILTER:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Discontinued &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Discontinued) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Featured &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Featured)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Discontinued &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Discontinued) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Products!Featured &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Featured)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Here, we’re using the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&amp;amp;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; operator to mean “and,” implying that
all three switch fields are used for the filtering operation. (If you’re used to
Excel, you can also use the &lt;span class=&quot;link binaryOperator&quot; name=&quot;*&quot;&gt;*&lt;/span&gt; operator.)&lt;/p&gt;

&lt;h3 id=&quot;the-critical-limitation&quot;&gt;The critical limitation&lt;/h3&gt;

&lt;p&gt;This approach has a fundamental problem: users must specify a value for
&lt;strong&gt;every&lt;/strong&gt; criterion. What if they want to see all products on sale but don’t
care whether they’re featured or discontinued? They can’t express that with
switch fields.&lt;/p&gt;

&lt;p&gt;This limitation makes the switch-field approach impractical for real use. We
need a way to represent “I don’t care” — which brings us to the actual
solution.&lt;/p&gt;

&lt;h2 id=&quot;the-real-solution-indeterminate-state&quot;&gt;The real solution: Indeterminate state&lt;/h2&gt;

&lt;p&gt;Switch fields can’t represent “I don’t care,” but text drop-down fields can.
Here’s the second example app using drop-downs that allow an indeterminate state:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 335px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=mgs5ne&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;Instead of switch fields, this app uses three text drop-down fields
named &lt;em&gt;OnSaleText&lt;/em&gt;, &lt;em&gt;DiscontinuedText&lt;/em&gt; and &lt;em&gt;FeaturedText&lt;/em&gt;. Each offers
three choices: &lt;strong&gt;Yes&lt;/strong&gt;, &lt;strong&gt;No&lt;/strong&gt; or leave it blank (representing “I
don’t care”).&lt;/p&gt;

&lt;p&gt;How it works:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Blank drop-downs: no filtering for that criterion.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Yes&lt;/strong&gt; or &lt;strong&gt;No&lt;/strong&gt;: filter based on that choice.&lt;/li&gt;
  &lt;li&gt;Multiple criteria: products must match all non-blank selections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Try selecting &lt;strong&gt;Yes&lt;/strong&gt; for &lt;strong&gt;On Sale&lt;/strong&gt; and leaving the other two blank. The
drop-down shows all products on sale, regardless of whether they’re
discontinued or featured. That’s the flexibility we need.&lt;/p&gt;

&lt;h3 id=&quot;implementation-details&quot;&gt;Implementation details&lt;/h3&gt;

&lt;p&gt;Since this app uses text drop-down fields instead of switch fields, we need
named values to convert the text selections (“Yes”, “No”, blank) into logical
values (TRUE, FALSE, blank) that the FILTER formula can use.&lt;/p&gt;

&lt;p&gt;For example, the formula for the &lt;em&gt;OnSale&lt;/em&gt; named value is:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(OnSaleText, &quot;Yes&quot;, TRUE, &quot;No&quot;, FALSE, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(OnSaleText; &quot;Yes&quot;; TRUE; &quot;No&quot;; FALSE; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(&lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt; selects between values, but &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; could also be used.)&lt;/p&gt;

&lt;p&gt;The formula for &lt;em&gt;FilteredProducts&lt;/em&gt; needs to handle blank values differently from
the switch field version:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Products!ProductName, (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale)) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(Discontinued) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!Discontinued &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Discontinued)) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(Featured) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!Featured &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Featured)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Products!ProductName; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale)) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(Discontinued) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!Discontinued &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Discontinued)) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(Featured) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!Featured &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Featured)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Let’s zero in on the &lt;em&gt;OnSale&lt;/em&gt; part of the second parameter:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(OnSale) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; (Products!OnSale &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; OnSale))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt; checks if &lt;em&gt;OnSale&lt;/em&gt; is blank, meaning no filtering
should occur for this criterion. The &lt;span class=&quot;link binaryOperator&quot; name=&quot;||&quot;&gt;||&lt;/span&gt; operator (or
&lt;span class=&quot;link binaryOperator&quot; name=&quot;+&quot;&gt;+&lt;/span&gt; in Excel) ensures that products are included if filtering is
not required.&lt;/p&gt;

&lt;p&gt;This formula produces a logical array whose elements are TRUE if the criterion
is blank (don’t care) or if it matches the corresponding column in the data
table.&lt;/p&gt;

&lt;p&gt;The crucial difference from the switch field version: &lt;span class=&quot;link function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt; checks
whether each criterion is blank, and &lt;span class=&quot;link binaryOperator&quot; name=&quot;||&quot;&gt;||&lt;/span&gt; (the OR operator)
ensures products are included when that criterion doesn’t matter to the user.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This technique requires named values, which are unavailable in Starter
plans. You can work around this by directly embedding the formulas instead of
using named value references.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2026/04/15/drop-downs-filter-optional.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2026/04/15/drop-downs-filter-optional.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Use initial values with formula-driven drop-downs</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Set initial values for formula-driven drop-downs using formulas that
  adapt to changing options.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;For drop-downs with fixed values, you set the initial selection by choosing a
value in Calcapp Creator. Simple and direct.&lt;/p&gt;

&lt;p&gt;But when drop-down values are &lt;a href=&quot;/blog/2025/10/15/drop-downs-values-formula.html&quot;&gt;determined using a
formula&lt;/a&gt;, those values aren’t known until the app
runs. The drop-down in Creator is disabled because there’s nothing to select
from yet.&lt;/p&gt;

&lt;p&gt;Instead, you set the initial value using a formula. Select &lt;strong&gt;InitialValue&lt;/strong&gt; from
the property drop-down in the inspector:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2026-02-27-drop-downs-initial-value/property-selector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2026-02-27-drop-downs-initial-value/property-selector.png&quot; alt=&quot;The property selector, with InitialValue being selected&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;example-formulas&quot;&gt;Example formulas&lt;/h2&gt;

&lt;h3 id=&quot;select-a-specific-value&quot;&gt;Select a specific value&lt;/h3&gt;

&lt;p&gt;If you know that 2 is always part of the available values, use this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;2&lt;/span&gt;&lt;/p&gt;

&lt;h3 id=&quot;select-the-first-value&quot;&gt;Select the first value&lt;/h3&gt;

&lt;p&gt;If you don’t know what values will be available and want the first one selected:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;, 1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;; 1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt; function selects the first value from
&lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; references the drop-down field
that the InitialValue property belongs to.&lt;/p&gt;

&lt;h3 id=&quot;select-the-last-value&quot;&gt;Select the last value&lt;/h3&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(Item.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(Item,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt; returns the number of values, which INDEX uses to select
the last one.&lt;/p&gt;

&lt;h3 id=&quot;select-the-middle-value&quot;&gt;Select the middle value&lt;/h3&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(Item.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(Item,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 2)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;dynamic-re-evaluation&quot;&gt;Dynamic re-evaluation&lt;/h2&gt;

&lt;p&gt;Traditionally, a field’s InitialValue property is only read when navigating to
the screen containing that field.&lt;/p&gt;

&lt;p&gt;For formula-driven drop-downs, InitialValue is now re-evaluated whenever the
available values change. This handles an important scenario: what happens when a
user’s selection becomes invalid?&lt;/p&gt;

&lt;p&gt;Consider two drop-downs: one for country, another for province. When the user
changes countries, the province list updates. But if they had already selected a
province, that selection likely becomes invalid since different countries rarely
share province names.&lt;/p&gt;

&lt;p&gt;Calcapp automatically re-evaluates InitialValue in this situation. If you’ve
used a formula like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INDEX(Item.Values, 1)&lt;/code&gt;, the first province in the new list
gets selected automatically, keeping the app in a valid state.&lt;/p&gt;

</description>
        <pubDate>Fri, 27 Feb 2026 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2026/02/27/drop-downs-initial-value.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2026/02/27/drop-downs-initial-value.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Fresh analytics insights from 2025</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We&apos;ve refined our analytics tools to gain deeper insights into how you&apos;re
  using Calcapp. Here are the most popular functions, button types and common
  errors from apps created in 2025.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;We have spent a lot of time refining the analytics tool we built to produce
&lt;a href=&quot;/blog/2025/01/09/popular-functions.html&quot;&gt;the list of the most popular formula functions&lt;/a&gt; to gain
deeper insights into how you’re using Calcapp. A year later, here’s a fresh
look at some of those data points, all pertaining only to apps created in
2025.&lt;/p&gt;

&lt;h2 id=&quot;most-popular-functions&quot;&gt;Most popular functions&lt;/h2&gt;

&lt;p&gt;If we look at the most popular functions used in only the apps created over the
past 12 months, we can see that the list hasn’t changed all that much:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Rank&lt;/th&gt;
    &lt;th&gt;Function name&lt;/th&gt;
    &lt;th&gt;Percentage&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;52.6%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;CUMPRINC&quot;&gt;CUMPRINC&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;14.1%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;3&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;12.9%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;4&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ROUND&quot;&gt;ROUND&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;11.8%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;5&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1.7%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;6&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1.0%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;7&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.9%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;8&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.9%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;9&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;RGB&quot;&gt;RGB&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.9%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;10&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.4%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;11&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;TONUMBER&quot;&gt;TONUMBER&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.3%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;12&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;13&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;LEN&quot;&gt;LEN&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;14&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;15&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;16&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;17&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;18&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;CONVERT&quot;&gt;CONVERT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.1%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;19&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;PMT&quot;&gt;PMT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.1%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;20&lt;/td&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;0.1%&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Interestingly, RGB has entered the top 10, pushing CHOOSE down to 25th place.
This suggests that more app creators are customizing their color schemes and
creating visually distinctive apps.&lt;/p&gt;

&lt;p&gt;(Or it could simply reflect that our new &lt;a href=&quot;/blog/2025/10/23/industry-templates.html&quot;&gt;templates&lt;/a&gt; use
RGB heavily.)&lt;/p&gt;

&lt;h2 id=&quot;most-popular-button-types&quot;&gt;Most popular button types&lt;/h2&gt;

&lt;p&gt;We also have a list of the most popular button types:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Rank&lt;/th&gt;
    &lt;th&gt;Button type&lt;/th&gt;
    &lt;th&gt;Percentage&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;
    &lt;td&gt;Reset&lt;/td&gt;
    &lt;td&gt;80.3%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;Email report&lt;/td&gt;
    &lt;td&gt;7.7%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;3&lt;/td&gt;
    &lt;td&gt;Go forward&lt;/td&gt;
    &lt;td&gt;4.4%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;4&lt;/td&gt;
    &lt;td&gt;Go back&lt;/td&gt;
    &lt;td&gt;2.1%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;5&lt;/td&gt;
    &lt;td&gt;Formula&lt;/td&gt;
    &lt;td&gt;2.0%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;6&lt;/td&gt;
    &lt;td&gt;Server relay&lt;/td&gt;
    &lt;td&gt;1.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;7&lt;/td&gt;
    &lt;td&gt;Open report&lt;/td&gt;
    &lt;td&gt;1.0%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;8&lt;/td&gt;
    &lt;td&gt;Browse&lt;/td&gt;
    &lt;td&gt;0.7%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;9&lt;/td&gt;
    &lt;td&gt;Clipboard copy&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;10&lt;/td&gt;
    &lt;td&gt;Compose email&lt;/td&gt;
    &lt;td&gt;0.2%&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;What we learned here is that reset buttons are by far the most popular. That was
the default when you pressed &lt;strong&gt;Add button&lt;/strong&gt; for years, but we changed it a few
years ago to email report buttons. That was apparently the wrong call, because
you have all dutifully changed those buttons to reset buttons!&lt;/p&gt;

&lt;p&gt;That alone is very useful information to us, because it’s actionable. We have
changed the default to reset buttons once more. Therefore, it appears that you
won’t have to change the button kind more than one time out of five, if
you’re a typical user.&lt;/p&gt;

&lt;h2 id=&quot;most-popular-screen-types&quot;&gt;Most popular screen types&lt;/h2&gt;

&lt;p&gt;We also have data on the most popular screen types:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Rank&lt;/th&gt;
    &lt;th&gt;Screen type&lt;/th&gt;
    &lt;th&gt;Percentage&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;
    &lt;td&gt;Form&lt;/td&gt;
    &lt;td&gt;89.6%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;List&lt;/td&gt;
    &lt;td&gt;7.7%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;3&lt;/td&gt;
    &lt;td&gt;Text&lt;/td&gt;
    &lt;td&gt;2.7%&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Nothing terribly surprising here. We’ll revise our handling of different
screens in the future, stay tuned.&lt;/p&gt;

&lt;h2 id=&quot;most-common-formula-errors&quot;&gt;Most common formula errors&lt;/h2&gt;

&lt;p&gt;What’s more interesting is that we now have data on the most common formula
errors you encounter:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Rank&lt;/th&gt;
    &lt;th&gt;Error kind&lt;/th&gt;
    &lt;th&gt;Percentage&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;
    &lt;td&gt;Invalid name reference&lt;/td&gt;
    &lt;td&gt;41.6%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;Circular dependency&lt;/td&gt;
    &lt;td&gt;21.8%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;3&lt;/td&gt;
    &lt;td&gt;Type mismatch (formula)&lt;/td&gt;
    &lt;td&gt;14.4%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;4&lt;/td&gt;
    &lt;td&gt;Type mismatch (operator)&lt;/td&gt;
    &lt;td&gt;10.5%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;5&lt;/td&gt;
    &lt;td&gt;Illegal ordering&lt;/td&gt;
    &lt;td&gt;3.6%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;6&lt;/td&gt;
    &lt;td&gt;Unknown function&lt;/td&gt;
    &lt;td&gt;3.4%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;7&lt;/td&gt;
    &lt;td&gt;Invalid text in formula&lt;/td&gt;
    &lt;td&gt;1.6%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;8&lt;/td&gt;
    &lt;td&gt;Action formula support required&lt;/td&gt;
    &lt;td&gt;1.1%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;9&lt;/td&gt;
    &lt;td&gt;Function parameter count&lt;/td&gt;
    &lt;td&gt;1.0%&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;10&lt;/td&gt;
    &lt;td&gt;Type mismatch (function)&lt;/td&gt;
    &lt;td&gt;0.8%&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;We obviously have our work cut out for us here. To be clear, this list
represents formula errors in apps that are stored on our server — which is
to say, apps probably abandoned by would-be app authors because of these
errors.&lt;/p&gt;

&lt;p&gt;(If you get frustrated, please get in touch! During working hours, we often
manage to respond immediately when you chat with us. We are also often quick
to respond to emails at &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;support@calcapp.net&lt;/a&gt;.)&lt;/p&gt;

&lt;h3 id=&quot;invalid-name-references&quot;&gt;Invalid name references&lt;/h3&gt;

&lt;p&gt;What this tells us is that referencing fields, buttons and the like is a
friction point. That particular error message links to &lt;a href=&quot;/learn/navigation.html#cross-screen-references&quot;&gt;this
page&lt;/a&gt;, which tries to explain how it works, when you
reference items from other screens, but perhaps this explanation isn’t clear
enough.&lt;/p&gt;

&lt;p&gt;Before we introduced our &lt;a href=&quot;/blog/2023/08/11/autocomplete.html&quot;&gt;autocomplete functionality&lt;/a&gt;, this
figure was actually higher, around 60%. The nice thing about autocomplete is
that you can type the name or label of, say, a field, and autocomplete inserts
the correct syntax automatically. We think that this has contributed to
getting this error down in our statistics, but it’s still concerning to see it
being so high.&lt;/p&gt;

&lt;h3 id=&quot;circular-references&quot;&gt;Circular references&lt;/h3&gt;

&lt;p&gt;Circular dependencies are tricky. Calcapp is fairly unique in that it diagnoses
these errors when you’re building your app (good) instead of just having your
app fail with an error message when you run it (bad). However, we have
struggled to produce a clear and actionable error message when circular
dependencies are found.&lt;/p&gt;

&lt;p&gt;So what are these circular dependencies? Plainly put, it’s when a field
indirectly or directly references itself in the formula.&lt;/p&gt;

&lt;p&gt;What’s the value of &lt;em&gt;Field1&lt;/em&gt; supposed to be? Why, it should be the value of
&lt;em&gt;Field1&lt;/em&gt; plus 2! Obviously, that can’t work, and the same goes if &lt;em&gt;Field1&lt;/em&gt;
depends on &lt;em&gt;Field2&lt;/em&gt;, which depends on &lt;em&gt;Field3&lt;/em&gt;, which depends on &lt;em&gt;Field1&lt;/em&gt;. It’s
difficult to get this across in an error message, and we’ll keep trying to make
it clearer.&lt;/p&gt;

&lt;h2 id=&quot;helping-us-serve-you-better&quot;&gt;Helping us serve you better&lt;/h2&gt;

&lt;p&gt;These insights into how you use Calcapp are invaluable for us. They guide our
development priorities and help us understand where our users struggle most.
While we’ve made great strides with features like autocomplete, the data shows
we still have important work ahead in making formula creation more intuitive
and error-resistant. Keep building those apps — and keep letting us know
where you get stuck!&lt;/p&gt;

</description>
        <pubDate>Mon, 05 Jan 2026 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2026/01/05/analytics-insights.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2026/01/05/analytics-insights.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Text-driven drop-down filtering</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Add a text field that filters drop-down options based on what users type,
  making it easier to work with large lists of values.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Text-driven%20drop-down%20filtering
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Drop-down fields with hundreds or thousands of values can be difficult to
navigate. Scrolling through long lists is tedious, and while desktop users can
type to jump to values, few know this feature exists and it doesn’t work on
mobile devices.&lt;/p&gt;

&lt;p&gt;The solution: add a text field that filters the drop-down. Users type their
search term, then open the drop-down to see only matching values. This makes
large lists manageable on any device.&lt;/p&gt;

&lt;h2 id=&quot;example-searching-names&quot;&gt;Example: Searching names&lt;/h2&gt;

&lt;p&gt;Here’s an example app with 100 names:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 160px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=ewjy8v&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;The drop-down shows only names matching the text entered in the search field.&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;

&lt;p&gt;This uses the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function. Here’s the formula for the
&lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; property of the drop-down:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Names, &lt;span class=&quot;function&quot; name=&quot;CONTAINS&quot;&gt;CONTAINS&lt;/span&gt;(Names, Search))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Names; &lt;span class=&quot;function&quot; name=&quot;CONTAINS&quot;&gt;CONTAINS&lt;/span&gt;(Names; Search))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Names&lt;/em&gt; is a &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named value&lt;/a&gt; containing the full list:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;, … }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &quot;Alice&quot;; &quot;Bob&quot;; &quot;Charlie&quot;; … }&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;case-insensitive-search&quot;&gt;Case-insensitive search&lt;/h2&gt;

&lt;p&gt;For case-insensitive filtering, use &lt;span class=&quot;link function&quot; name=&quot;LOWER&quot;&gt;LOWER&lt;/span&gt; to convert both the
search term and the names to lowercase:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Names, &lt;span class=&quot;function&quot; name=&quot;CONTAINS&quot;&gt;CONTAINS&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;LOWER&quot;&gt;LOWER&lt;/span&gt;(Names), &lt;span class=&quot;function&quot; name=&quot;LOWER&quot;&gt;LOWER&lt;/span&gt;(Search)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Names; &lt;span class=&quot;function&quot; name=&quot;CONTAINS&quot;&gt;CONTAINS&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;LOWER&quot;&gt;LOWER&lt;/span&gt;(Names); &lt;span class=&quot;function&quot; name=&quot;LOWER&quot;&gt;LOWER&lt;/span&gt;(Search)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Now searching for “alice”, “ALICE” or “Alice” all produce the same results.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This technique requires named values, which are not available in our
Starter plans. You can work around this by directly embedding the array formula
instead of using a named value reference.&lt;/p&gt;

</description>
        <pubDate>Sun, 14 Dec 2025 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/12/14/drop-downs-filter-text-field.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/12/14/drop-downs-filter-text-field.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Use XLOOKUP with multiple criteria</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Combine multiple search criteria in XLOOKUP using AND, OR and parentheses to
  find exactly the data you need.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Use%20XLOOKUP%20with%20multiple%20criteria
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; is excellent for finding data in tables. Let’s
explore how to use it with multiple search criteria using this venue
table:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Venue&lt;/th&gt;
      &lt;th&gt;Type&lt;/th&gt;
      &lt;th&gt;Location&lt;/th&gt;
      &lt;th&gt;Capacity&lt;/th&gt;
      &lt;th&gt;Rate&lt;/th&gt;
      &lt;th&gt;AV&lt;/th&gt;
      &lt;th&gt;Catering&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Grand Ballroom&lt;/td&gt;
      &lt;td&gt;Hotel&lt;/td&gt;
      &lt;td&gt;Downtown&lt;/td&gt;
      &lt;td&gt;500&lt;/td&gt;
      &lt;td&gt;5000&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Conference Center A&lt;/td&gt;
      &lt;td&gt;Conference&lt;/td&gt;
      &lt;td&gt;Business District&lt;/td&gt;
      &lt;td&gt;200&lt;/td&gt;
      &lt;td&gt;2000&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Community Hall&lt;/td&gt;
      &lt;td&gt;Community&lt;/td&gt;
      &lt;td&gt;Suburbs&lt;/td&gt;
      &lt;td&gt;150&lt;/td&gt;
      &lt;td&gt;800&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Rooftop Terrace&lt;/td&gt;
      &lt;td&gt;Outdoor&lt;/td&gt;
      &lt;td&gt;Downtown&lt;/td&gt;
      &lt;td&gt;100&lt;/td&gt;
      &lt;td&gt;1500&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Executive Boardroom&lt;/td&gt;
      &lt;td&gt;Conference&lt;/td&gt;
      &lt;td&gt;Business District&lt;/td&gt;
      &lt;td&gt;25&lt;/td&gt;
      &lt;td&gt;500&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;FALSE&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Garden Pavilion&lt;/td&gt;
      &lt;td&gt;Outdoor&lt;/td&gt;
      &lt;td&gt;Suburbs&lt;/td&gt;
      &lt;td&gt;80&lt;/td&gt;
      &lt;td&gt;1200&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
      &lt;td&gt;TRUE&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The table is created using the &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data editor&lt;/a&gt; and stored in a form
screen named &lt;em&gt;Venues&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;basic-xlookup-usage&quot;&gt;Basic XLOOKUP usage&lt;/h2&gt;

&lt;p&gt;Normally, you use XLOOKUP to find exact matches:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(&quot;Hotel&quot;, Venues!Type, Venues!Venue)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(&quot;Hotel&quot;; Venues!Type; Venues!Venue)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This finds the first venue where the type equals “Hotel” and returns
“Grand Ballroom”.&lt;/p&gt;

&lt;h2 id=&quot;moving-to-the-true-technique&quot;&gt;Moving to the TRUE technique&lt;/h2&gt;

&lt;p&gt;You can achieve the same result by moving the equality check into the search
criteria:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Hotel&quot;, Venues!Venue)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Hotel&quot;; Venues!Venue)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Here’s what happens: XLOOKUP evaluates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Venues!Type = &quot;Hotel&quot;&lt;/code&gt; for each row.
This comparison returns TRUE for “Grand Ballroom” (because its type is “Hotel”)
and FALSE for all other venues. Since we’re looking for TRUE, XLOOKUP finds the
first row where the comparison is TRUE and returns “Grand Ballroom”.&lt;/p&gt;

&lt;p&gt;Both formulas return the same result, but the second approach opens up powerful
possibilities. Instead of a simple equality check, you can use any logical
expression that evaluates to TRUE or FALSE.&lt;/p&gt;

&lt;h2 id=&quot;building-complex-search-criteria&quot;&gt;Building complex search criteria&lt;/h2&gt;

&lt;p&gt;Once you’re searching for TRUE, you can combine multiple conditions using
logical operators. Calcapp supports these operators that are common in
programming languages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&amp;amp;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; means “and” — both conditions must be TRUE.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;link binaryOperator&quot; name=&quot;||&quot;&gt;||&lt;/span&gt; means “or” — either condition can be TRUE.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;link unaryOperator&quot; name=&quot;!&quot;&gt;!&lt;/span&gt; means “not” — turns TRUE into FALSE and vice versa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(You can also use the function equivalents &lt;span class=&quot;link function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;, but the operators are often easier to read.)&lt;/p&gt;

&lt;p&gt;For example, to find conference venues with capacity of at least 100:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, (Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Conference&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Venues!Capacity &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 100), Venues!Venue)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; (Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Conference&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Venues!Capacity &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 100); Venues!Venue)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This returns “Conference Center A” — the first venue meeting both criteria.&lt;/p&gt;

&lt;h2 id=&quot;demo-app&quot;&gt;Demo app&lt;/h2&gt;

&lt;p&gt;Here’s a working example that lets you experiment with different search
combinations:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 575px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=x0ws8w&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Set venue type to “Hotel” — you’ll find “Grand Ballroom” at $5000.&lt;/li&gt;
  &lt;li&gt;Now add a maximum budget of $4000 — the search will find “Hotel Atrium”
instead.&lt;/li&gt;
  &lt;li&gt;Change venue type to “Outdoor” — you’ll find “Rooftop Terrace”.&lt;/li&gt;
  &lt;li&gt;Toggle “Requires catering” on — now it finds “Garden Pavilion” instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-the-demo-app-works&quot;&gt;How the demo app works&lt;/h2&gt;

&lt;p&gt;The demo app shows several search criteria working together:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Venue type&lt;/strong&gt;: Drop-down to filter by hotel, conference, community or outdoor
venues.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Minimum capacity&lt;/strong&gt;: Number field for required seating.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Maximum budget&lt;/strong&gt;: Number field for budget constraints.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Requires AV equipment&lt;/strong&gt;: Switch field for audio/visual needs.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Requires catering&lt;/strong&gt;: Switch field for food service needs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you change any criteria, the app immediately shows the first venue that
matches all your requirements.&lt;/p&gt;

&lt;h2 id=&quot;the-xlookup-formula&quot;&gt;The XLOOKUP formula&lt;/h2&gt;

&lt;p&gt;Here’s the core formula that powers the search:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, (VenueType &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; VenueType) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MinCapacity) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Capacity &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; MinCapacity) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MaxBudget) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Rate &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; MaxBudget) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredAV &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!AV) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredCatering &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Catering), Venues!Venue, &quot;No matches found&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; (VenueType &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; VenueType) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MinCapacity) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Capacity &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; MinCapacity) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MaxBudget) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Rate &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; MaxBudget) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredAV &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!AV) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredCatering &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Catering); Venues!Venue; &quot;No matches found&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This single formula handles all the search logic. The following sections explain
its constituent parts:&lt;/p&gt;

&lt;h3 id=&quot;venue-type&quot;&gt;Venue type&lt;/h3&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(VenueType &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; VenueType)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(VenueType &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Type &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; VenueType)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Matches if no type selected &lt;em&gt;or&lt;/em&gt; if venue type matches selection.&lt;/p&gt;

&lt;h3 id=&quot;capacity&quot;&gt;Capacity&lt;/h3&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MinCapacity) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Capacity &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt;    MinCapacity)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MinCapacity) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Capacity &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt;    MinCapacity)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Matches if no minimum specified &lt;em&gt;or&lt;/em&gt; if venue has enough capacity.&lt;/p&gt;

&lt;h3 id=&quot;budget&quot;&gt;Budget&lt;/h3&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MaxBudget) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Rate &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; MaxBudget)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(MaxBudget) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Rate &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; MaxBudget)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Matches if no budget specified &lt;em&gt;or&lt;/em&gt; if venue is within budget.&lt;/p&gt;

&lt;h3 id=&quot;av-equipment&quot;&gt;AV equipment&lt;/h3&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredAV &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!AV)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredAV &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!AV)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Matches if audio-visual equipment not required &lt;em&gt;or&lt;/em&gt; if venue has AV.&lt;/p&gt;

&lt;h3 id=&quot;catering&quot;&gt;Catering&lt;/h3&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredCatering &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Catering)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredCatering &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!Catering)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Matches if catering not required &lt;em&gt;or&lt;/em&gt; if venue has catering.&lt;/p&gt;

&lt;p&gt;All conditions are combined with &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&amp;amp;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;, so venues must meet every
specified criterion.&lt;/p&gt;

&lt;h2 id=&quot;techniques-demonstrated&quot;&gt;Techniques demonstrated&lt;/h2&gt;

&lt;h3 id=&quot;optional-criteria-handling&quot;&gt;Optional criteria handling&lt;/h3&gt;

&lt;p&gt;In order to make criteria optional, the formula uses this pattern:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(field) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; condition&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;(field) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; condition&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If a search field is blank, that criterion is ignored. If it has a value, the
venue must match it.&lt;/p&gt;

&lt;h3 id=&quot;switch-field-logic&quot;&gt;Switch field logic&lt;/h3&gt;

&lt;p&gt;For switch fields, the formula uses &lt;span class=&quot;formula decimalpoint&quot;&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredAV &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!AV)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;RequiredAV &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Venues!AV)&lt;/span&gt;. When the switch is FALSE (not required),
the condition is always TRUE. When the switch is TRUE (required),
venues must have that amenity.&lt;/p&gt;

&lt;h3 id=&quot;multiple-result-fields&quot;&gt;Multiple result fields&lt;/h3&gt;

&lt;p&gt;The app shows venue name, location, capacity and rate by using the
same search criteria in separate XLOOKUP formulas:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, [ same criteria ], Venues!Location, &quot;&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; [ same criteria ]; Venues!Location; &quot;&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, [ same criteria ], Venues!Capacity, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; [ same criteria ]; Venues!Capacity; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, [ same criteria ], Venues!Rate, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; [ same criteria ]; Venues!Rate; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This ensures all displayed information comes from the same matching venue.&lt;/p&gt;

&lt;h2 id=&quot;the-true-search-technique&quot;&gt;The TRUE search technique&lt;/h2&gt;

&lt;p&gt;The takeaway is that you can use TRUE as the lookup value instead of searching
for specific data. When you write:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, [ some complex condition ], [
Return array ])&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; [ some complex condition ]; [
Return array ])&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;XLOOKUP evaluates the complex condition for every row, looking for the first
position where it equals TRUE. This lets you use any logical expression as your
search criteria.&lt;/p&gt;

&lt;p&gt;This technique works with any combination of:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Comparison operators: &lt;span class=&quot;link binaryOperator&quot; name=&quot;=&quot;&gt;=&lt;/span&gt;, &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;lt;&amp;gt;&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;,
&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;lt;&quot;&gt;&amp;lt;&lt;/span&gt;, &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;gt;&quot;&gt;&amp;gt;&lt;/span&gt;, &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;lt;=&quot;&gt;&amp;lt;=&lt;/span&gt;, &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;gt;=&quot;&gt;&amp;gt;=&lt;/span&gt;.&lt;/li&gt;
  &lt;li&gt;Logical operators: &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&amp;amp;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;, &lt;span class=&quot;link binaryOperator&quot; name=&quot;||&quot;&gt;||&lt;/span&gt;, &lt;span class=&quot;link unaryOperator&quot; name=&quot;!&quot;&gt;!&lt;/span&gt;.&lt;/li&gt;
  &lt;li&gt;Parentheses for grouping complex conditions.&lt;/li&gt;
  &lt;li&gt;Field references and literal values.&lt;/li&gt;
  &lt;li&gt;Functions like &lt;span class=&quot;link function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt; for optional criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;building-your-own-search-apps&quot;&gt;Building your own search apps&lt;/h2&gt;

&lt;p&gt;This approach works for any data table where you need sophisticated filtering:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Product catalogs&lt;/strong&gt;: Search by category, price range, features and
availability.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Employee directories&lt;/strong&gt;: Filter by department, role, location and skills.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Event listings&lt;/strong&gt;: Find events by date, type, location and ticket price.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Inventory systems&lt;/strong&gt;: Search by product type, quantity, supplier and status.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern is always the same: combine multiple conditions with logical
operators, then let XLOOKUP find the first matching row. Use the same criteria
in multiple formulas to retrieve different fields from that row.&lt;/p&gt;

&lt;p&gt;Try the demo app above to experiment with different search combinations and see
how multiple criteria can help you find exactly the data you need.&lt;/p&gt;

</description>
        <pubDate>Fri, 14 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/11/14/xlookup-multiple-criteria.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/11/14/xlookup-multiple-criteria.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Bug report: Some drop-down fields lost their values</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our October 15 update introduced a serious error affecting number drop-down
  fields. We have deployed an automatic fix for the vast majority of affected
  apps.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2025/10/15/release.html&quot;&gt;October 15 release&lt;/a&gt; unfortunately introduced a subtle
error that significantly impacted app functionality. A small percentage of all
number drop-down fields had their values replaced by zeroes.&lt;/p&gt;

&lt;p&gt;While this only affected 0.45% of all apps, that still represents many hundreds
of apps, and we sincerely apologize to everyone who was affected by this issue.&lt;/p&gt;

&lt;h2 id=&quot;our-response&quot;&gt;Our response&lt;/h2&gt;

&lt;p&gt;As soon as we became aware of the problem, we worked through the weekend to
develop the tools needed to fix the issue properly. We have now deployed an
automatic fix to the vast majority of all affected apps, and you should find
that your app works correctly again.&lt;/p&gt;

&lt;p&gt;However, for apps that were modified after our October 15 release, we couldn’t
automatically apply the fix because doing so would have meant rolling back all
changes you made from that date forward. We have reached out to all affected
users through email and offered our assistance. We would be happy to restore
your app to a version from October 15 with working number drop-down menus, but
we need your confirmation first.&lt;/p&gt;

&lt;h2 id=&quot;what-happened&quot;&gt;What happened?&lt;/h2&gt;

&lt;p&gt;Apps built with Calcapp undergo a migration process when we release major
updates. Apps have an internal format that is hidden from view, and this format
is updated every time we make a major release. We have a heavily-tested,
automatic process for upgrading all apps before we release a new Calcapp
version.&lt;/p&gt;

&lt;p&gt;This particular new version was number 13 (perhaps no coincidence?), and our
automatic process for converting all apps from version 12 to version 13 was
evidently not tested thoroughly enough.&lt;/p&gt;

&lt;p&gt;As you may recall, the headline feature of our October release was the ability
to &lt;a href=&quot;/blog/2025/10/15/drop-downs-values-formula.html&quot;&gt;set drop-down field values using formulas&lt;/a&gt;. This
required converting all drop-down values from one format to another
automatically. While this worked perfectly in our controlled testing
environment, it failed for a small percentage of real-world apps, explaining why
their values were replaced by zeroes.&lt;/p&gt;

&lt;h2 id=&quot;our-commitment&quot;&gt;Our commitment&lt;/h2&gt;

&lt;p&gt;This is the first time our migration process has introduced a data loss bug, and
we sincerely apologize for any inconvenience this caused. We’re happy to report
that almost all apps have now been fixed and work correctly again. We are taking
steps to ensure that this won’t happen again.&lt;/p&gt;

</description>
        <pubDate>Tue, 04 Nov 2025 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/11/04/dropdown-bug.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/11/04/dropdown-bug.html</guid>
        
        <category>Bug report</category>
        
        
      </item>
    
      <item>
        <title>Feature: 20 new industry-specific templates</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We&apos;ve added 20 comprehensive templates covering major industries, from
  agriculture to transportation. Each template includes realistic calculations,
  giving you a solid foundation for building apps in your field.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Building an app from scratch can be daunting, especially when you’re not sure
how to structure calculations for your specific industry. That’s why we’ve
created 20 new templates covering major business verticals, each designed to
showcase real-world calculations and best practices.&lt;/p&gt;

&lt;p&gt;These new templates are front and center when you open Calcapp Creator and
select the &lt;strong&gt;New app&lt;/strong&gt; tab, organized with emoji icons for easy recognition:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-23-industry-templates/new-app-tab.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-23-industry-templates/new-app-tab.png&quot; alt=&quot;The New app tab showing industry-specific templates with emoji             icons&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each template includes multiple screens with realistic data and calculations
that demonstrate common use cases for that industry. Whether you’re calculating
construction costs, patient BMI scores, marketing campaign ROI or energy
consumption, these templates provide a starting point with actual formulas you
can build upon.&lt;/p&gt;

&lt;p&gt;Previously, our template collection was hit and miss. While we’ve created close
to 30 templates over the years, they were never comprehensive enough to cover
the breadth of industries using Calcapp. These new templates fill that gap.&lt;/p&gt;

&lt;h2 id=&quot;an-excel-first-perspective&quot;&gt;An Excel-first perspective&lt;/h2&gt;

&lt;p&gt;We had outside help when creating these templates, and this brings an
interesting perspective: they were built using expert-level Excel knowledge but
from a newcomer’s perspective to Calcapp. This means you’ll find approaches that
Excel users will recognize immediately, such as using the &lt;span class=&quot;link function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt;
function instead of our streamlined &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; function (which also
handles many conditions).&lt;/p&gt;

&lt;p&gt;These apps use color-coding pervasively for result values. They use the same
colors in many places and do so by repeating &lt;span class=&quot;link function&quot; name=&quot;RGB&quot;&gt;RGB&lt;/span&gt; formulas with
the same parameters everywhere.&lt;/p&gt;

&lt;p&gt;As software engineers, we typically prefer abstraction and keeping code DRY
(Don’t Repeat Yourself). We would likely have created named values with color
values that we could reference from formulas instead of duplicating RGB
parameters everywhere.&lt;/p&gt;

&lt;p&gt;However, we recognize that many users prefer the direct approach they’re
familiar with from Excel — similar to using cell references instead of named
ranges. These templates reflect that real-world preference, showing that there
are multiple valid ways to structure your apps.&lt;/p&gt;

&lt;h2 id=&quot;beyond-the-blank-template&quot;&gt;Beyond the Blank template&lt;/h2&gt;

&lt;p&gt;We’ve also added a new &lt;strong&gt;Blank with back end&lt;/strong&gt; template that takes advantage of
our new &lt;a href=&quot;/blog/2025/10/15/first-screen.html&quot;&gt;FirstScreen feature&lt;/a&gt;. This template starts you with a
structure for organizing hidden calculations, data tables and other back-office
logic that powers your app without cluttering the user interface.&lt;/p&gt;

&lt;p&gt;This approach demonstrates how to separate your app’s logic from its
presentation, keeping complex calculations organized behind the scenes while
presenting a clean interface to users.&lt;/p&gt;

&lt;p&gt;The comprehensive nature of these templates means you can see how experienced
app builders structure their work, from simple calculations to complex
multi-screen workflows. Each template serves as both a starting point and a
learning resource.&lt;/p&gt;

</description>
        <pubDate>Thu, 23 Oct 2025 11:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/23/industry-templates.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/23/industry-templates.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Emojis in app names are now highlighted</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  When your app name starts with an emoji, we now display it larger and more
  prominently, making your app list easier to scan and navigate. This builds
  on what many users already do to organize their apps.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Many Calcapp users have discovered a clever way to organize their apps: they
start app names with an emoji to create visual categories. A green checkmark for
approved apps, a construction emoji for building projects, a heart for favorites
— emojis make it easier to scan long lists of apps at a glance.&lt;/p&gt;

&lt;p&gt;We’ve been watching this trend and decided to make it even better. When your
app name starts with an emoji, Calcapp now recognizes it and displays the
emoji larger and more prominently above the app name, similar to how text
messages display emoji-only messages in a larger size.&lt;/p&gt;

&lt;p&gt;This enhancement makes your emoji-categorized apps even easier to identify and
navigate, especially when you have many apps in your account. The larger emoji
serves as a visual anchor that helps you quickly find what you’re looking for.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-23-emoji-highlighting/open-app-tab.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-23-emoji-highlighting/open-app-tab.png&quot; alt=&quot;The Open app tab showing apps with highlighted emoji icons&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;recognition-of-user-innovation&quot;&gt;Recognition of user innovation&lt;/h2&gt;

&lt;p&gt;This feature represents something we love about our user community: you often
find creative solutions that inspire us to build better tools. We’ve seen
users adopt emoji prefixes organically as a way to bring order to their app
collections, and this feature is our way of recognizing and enhancing that
innovation.&lt;/p&gt;

&lt;p&gt;Whether you’re using emojis to indicate status, categorize by industry or
simply make your apps more visually appealing, the enhanced display makes
these organizational systems more effective.&lt;/p&gt;

&lt;h2 id=&quot;a-lighthearted-milestone&quot;&gt;A lighthearted milestone&lt;/h2&gt;

&lt;p&gt;This may well be the least significant Calcapp feature ever to receive its own
&lt;a href=&quot;/blog/tag/feature.html&quot;&gt;Feature blog post&lt;/a&gt;. But sometimes the smallest improvements
make the biggest difference in daily workflows. When you’re managing dozens or
hundreds of apps, every bit of visual clarity helps.&lt;/p&gt;

&lt;p&gt;The new highlighting works automatically — there’s nothing to configure or
enable. Just start your app name with an emoji and watch it become more
prominent in your app list.&lt;/p&gt;

&lt;p&gt;Want to learn more creative ways to use emojis in your app organization? Check
out our &lt;a href=&quot;/blog/2025/10/23/emoji-app-organization.html&quot;&gt;tips for organizing apps with emojis&lt;/a&gt; for inspiration and
practical strategies.&lt;/p&gt;

</description>
        <pubDate>Thu, 23 Oct 2025 10:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/23/emoji-highlighting.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/23/emoji-highlighting.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Tip: Organize your apps with emojis</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Using emojis as the first character of your app names creates powerful
  visual organization systems. With Calcapp now highlighting these emojis
  prominently, your app management becomes even more efficient.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;App names that start with emojis aren’t just fun — they’re a powerful
organizational tool. With &lt;a href=&quot;/blog/2025/10/23/emoji-highlighting.html&quot;&gt;emojis now highlighted prominently&lt;/a&gt;
in your app list, you can create sophisticated categorization systems that
make managing large collections of apps effortless.&lt;/p&gt;

&lt;h2 id=&quot;adding-emojis-to-your-system&quot;&gt;Adding emojis to your system&lt;/h2&gt;

&lt;p&gt;Before exploring organization strategies, here’s how to insert emojis on
different platforms:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Windows&lt;/strong&gt;: Use &lt;kbd&gt;Windows key&lt;/kbd&gt;+&lt;kbd&gt;.&lt;/kbd&gt; to open the emoji panel,
or search for “Character Map” in the Start menu for the traditional character
selection tool.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;macOS&lt;/strong&gt;: Press &lt;kbd&gt;Control&lt;/kbd&gt;+&lt;kbd&gt;Command&lt;/kbd&gt;+&lt;kbd&gt;Space&lt;/kbd&gt; to
open the emoji picker, or use the Edit menu and select “Emoji &amp;amp; Symbols.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Linux (GNOME)&lt;/strong&gt;: Open the “Characters” application from your application
menu to browse and insert emojis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve added an emoji as the first character of your app name, Calcapp
will automatically display it larger and more prominently in your app list.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-23-emoji-app-organization/open-app-tab.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-23-emoji-app-organization/open-app-tab.png&quot; alt=&quot;The Open app tab showing apps organized with emoji categories&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;status-based-organization&quot;&gt;Status-based organization&lt;/h2&gt;

&lt;p&gt;Use emojis to communicate the status of your apps at a glance:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;✅ &lt;strong&gt;Green checkmark&lt;/strong&gt;: Apps currently in production or approved for use&lt;/li&gt;
  &lt;li&gt;❌ &lt;strong&gt;Red X&lt;/strong&gt;: Apps that need fixes or haven’t passed quality checks&lt;/li&gt;
  &lt;li&gt;🚧 &lt;strong&gt;Construction sign&lt;/strong&gt;: Apps under active development&lt;/li&gt;
  &lt;li&gt;🔒 &lt;strong&gt;Lock&lt;/strong&gt;: Private or restricted-access apps&lt;/li&gt;
  &lt;li&gt;⭐ &lt;strong&gt;Star&lt;/strong&gt;: Your most important or frequently used apps&lt;/li&gt;
  &lt;li&gt;🧪 &lt;strong&gt;Test tube&lt;/strong&gt;: Experimental or beta versions&lt;/li&gt;
  &lt;li&gt;📋 &lt;strong&gt;Clipboard&lt;/strong&gt;: Template apps you duplicate for new projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This system lets you quickly identify which apps are ready for users, which
need attention and which are works in progress.&lt;/p&gt;

&lt;h2 id=&quot;industry-categorization&quot;&gt;Industry categorization&lt;/h2&gt;

&lt;p&gt;For consultants or agencies managing apps across multiple industries:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;🏥 &lt;strong&gt;Healthcare&lt;/strong&gt;: Patient calculators, dosage apps, BMI tools&lt;/li&gt;
  &lt;li&gt;🏗️ &lt;strong&gt;Construction&lt;/strong&gt;: Cost estimators, material calculators, project planners&lt;/li&gt;
  &lt;li&gt;💰 &lt;strong&gt;Finance&lt;/strong&gt;: Loan calculators, investment tools, budget planners&lt;/li&gt;
  &lt;li&gt;📚 &lt;strong&gt;Education&lt;/strong&gt;: Grade calculators, assignment trackers, study tools&lt;/li&gt;
  &lt;li&gt;🍕 &lt;strong&gt;Food service&lt;/strong&gt;: Recipe scalers, cost calculators, inventory trackers&lt;/li&gt;
  &lt;li&gt;🚗 &lt;strong&gt;Automotive&lt;/strong&gt;: Maintenance schedules, fuel efficiency, parts pricing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you sort your apps by name, all apps in the same category will appear
together, making project management much simpler.&lt;/p&gt;

&lt;h2 id=&quot;client-based-systems&quot;&gt;Client-based systems&lt;/h2&gt;

&lt;p&gt;Service providers can organize apps by client using distinctive emojis:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;🏢 &lt;strong&gt;Building&lt;/strong&gt;: Corporate clients&lt;/li&gt;
  &lt;li&gt;🏪 &lt;strong&gt;Shop&lt;/strong&gt;: Retail clients&lt;/li&gt;
  &lt;li&gt;🎯 &lt;strong&gt;Target&lt;/strong&gt;: Marketing agencies&lt;/li&gt;
  &lt;li&gt;🔧 &lt;strong&gt;Wrench&lt;/strong&gt;: Manufacturing clients&lt;/li&gt;
  &lt;li&gt;💊 &lt;strong&gt;Pill&lt;/strong&gt;: Healthcare organizations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might even assign specific emojis to individual major clients, making it
easy to find all apps related to a particular account.&lt;/p&gt;

&lt;h2 id=&quot;version-management-with-emojis&quot;&gt;Version management with emojis&lt;/h2&gt;

&lt;p&gt;Combine emojis with our &lt;a href=&quot;/blog/2017/05/25/versions.html&quot;&gt;app versioning strategy&lt;/a&gt; for even better
organization:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;📱 &lt;strong&gt;Mobile phone&lt;/strong&gt;: Current production version&lt;/li&gt;
  &lt;li&gt;🔄 &lt;strong&gt;Refresh&lt;/strong&gt;: Updated version awaiting approval&lt;/li&gt;
  &lt;li&gt;📦 &lt;strong&gt;Package&lt;/strong&gt;: Archived versions for reference&lt;/li&gt;
  &lt;li&gt;🎯 &lt;strong&gt;Target&lt;/strong&gt;: Beta versions for testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since you can &lt;a href=&quot;/blog/2017/05/25/versions.html&quot;&gt;create unlimited copies of your apps&lt;/a&gt; for free,
emoji-based version control helps you track the evolution of your work without
cluttering your app list.&lt;/p&gt;

&lt;h2 id=&quot;advanced-sorting-strategies&quot;&gt;Advanced sorting strategies&lt;/h2&gt;

&lt;p&gt;App lists can be sorted by modification time (default) or alphabetically by
name. When sorting by name, apps are actually sorted by their emoji first,
then by the remaining text. This creates powerful grouping opportunities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Use numbered emojis (1️⃣, 2️⃣, 3️⃣) to force specific ordering&lt;/li&gt;
  &lt;li&gt;Group related apps with similar emojis (🟢, 🟡, 🔴 for traffic light status)&lt;/li&gt;
  &lt;li&gt;Use seasonal emojis (🌸, ☀️, 🍂, ❄️) for time-sensitive apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is consistency — develop a system that makes sense for your workflow
and stick with it.&lt;/p&gt;

&lt;h2 id=&quot;managing-large-app-collections&quot;&gt;Managing large app collections&lt;/h2&gt;

&lt;p&gt;We have around 600 apps in our account, and emoji organization has become
essential for navigation. Whether you’re a power user with dozens of apps or
just getting started, emoji categorization scales with your needs.&lt;/p&gt;

&lt;p&gt;Consider creating a simple legend document that explains your emoji system,
especially if you work with teammates who need to understand your
organizational scheme.&lt;/p&gt;

&lt;p&gt;With emojis now highlighted prominently in Calcapp, your visual organization
system becomes even more effective, turning your app list into an intuitive,
scannable dashboard of your work.&lt;/p&gt;

</description>
        <pubDate>Thu, 23 Oct 2025 09:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/23/emoji-app-organization.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/23/emoji-app-organization.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Release: Our October, 2025 update is here</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Define drop-down values with formulas to enable filtering, sorting
  and multi-level menus. Launch options and customizable first screens
  let apps adapt to their context, including the host page. QR codes
  and a redesigned workflow make publishing apps effortless.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;


&lt;a href=&quot;/assets/media/blog/2025-10-15-release/hero.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-release/hero.png&quot;
       alt=&quot;App publishing workflow diagram showcasing the new release features&quot;
       class=&quot;large-image no-shadow center-image&quot;&gt;&lt;/a&gt;

&lt;h2&gt;What&apos;s new?&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Formula-driven drop-down values.&lt;/strong&gt;
    Drop-down fields can now use formulas to determine their values, enabling
    data table integration, multi-level menus and dynamic filtering.
    &lt;a href=&quot;/blog/2025/10/15/drop-downs-values-formula.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Redesigned publishing workflow.&lt;/strong&gt;
    We&apos;ve redesigned the publishing workflow to prevent accidental
    overwrites and give you better control over when changes go live.
    &lt;a href=&quot;/blog/2025/10/15/publishing-workflow.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Launch options.&lt;/strong&gt;
    Build a single app that adapts to different contexts, including the host
    page for embedded apps. Launch options are accessible from formulas.
    &lt;a href=&quot;/blog/2025/10/15/launch-options.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Customize the first screen shown.&lt;/strong&gt;
    Control which screen users see first based on user roles, launch options or
    saved field values. This is also a great opportunity to hide data tables and
    calculations.
    &lt;a href=&quot;/blog/2025/10/15/first-screen.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;QR codes for your apps.&lt;/strong&gt;
    QR codes for your apps make it easy to test and share your apps across
    devices.
    &lt;a href=&quot;/blog/2025/10/15/qr-code.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Bulgarian language support.&lt;/strong&gt;
    Thanks to a user in Bulgaria, we now support 31 fully translated
    languages, making Calcapp accessible to an even broader global audience.
    &lt;a href=&quot;/blog/2025/10/15/bulgarian.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Tips for getting the most out of Calcapp&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Populate drop-downs from data tables.&lt;/strong&gt;
    Pull values directly from data table columns, eliminating manual copying
    and keeping everything synchronized automatically. Changes to your data
    tables instantly reflect in all connected drop-downs.
    &lt;a href=&quot;/blog/2025/10/15/drop-downs-table-values.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Multi-level drop-downs.&lt;/strong&gt;
    Create drop-downs that adapt their options based on selections in other
    drop-downs. Perfect for country/state selections, category/product
    filtering, and other hierarchical data relationships.
    &lt;a href=&quot;/blog/2025/10/15/drop-downs-multi-level.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Quality improvements&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Formula reliability improvements.&lt;/strong&gt;
    Numerous edge cases in formula evaluation have been resolved, making
    complex formulas more reliable and predictable.
    &lt;a href=&quot;/blog/2025/10/15/formula-bugs.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Creator stability enhancements.&lt;/strong&gt;
    We&apos;ve fixed two annoying bugs in Calcapp Creator that were hard to
    reproduce. Formula popups now dismiss properly and multi-selection
    works reliably.
    &lt;a href=&quot;/blog/2025/10/15/creator-bugs.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Miscellaneous&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Revised learning guides.&lt;/strong&gt;
    We&apos;ve overhauled our learning guides with clearer headlines, bullet points
    instead of prose and more concise explanations to make them easier to scan.
    &lt;a href=&quot;/blog/2025/10/15/revised-guides.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Template apps from our tips.&lt;/strong&gt;
    Eight tip blog posts with demo apps now have template versions you can open
    directly in Calcapp Creator, making advanced techniques easier to learn.
    &lt;a href=&quot;/blog/2025/10/15/tip-templates.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;What&apos;s next&lt;/h2&gt;
&lt;p&gt;
  In the coming year, we&apos;ll be sharing more tips and techniques that build
  on these new capabilities, showing you how to create increasingly
  sophisticated apps with the tools now at your disposal.
&lt;/p&gt;

&lt;p&gt;
  We&apos;re also working on a major new project that will expand Calcapp&apos;s
  capabilities in significant ways. Stay tuned for more information in 2026.
&lt;/p&gt;
</description>
        <pubDate>Wed, 15 Oct 2025 12:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/release.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/release.html</guid>
        
        <category>Release</category>
        
        
      </item>
    
      <item>
        <title>Feature: Formula-driven drop-down values</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Drop-down fields can now use formulas to determine their values, enabling
  data table integration, multi-level menus and dynamic filtering.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Drop-down fields are essential for letting users select from lists of options.
With this &lt;a href=&quot;/blog/2025/10/15/release.html&quot;&gt;release&lt;/a&gt;, they become much more versatile: you
can now assign formulas to the Values property of &lt;span class=&quot;link property&quot; parent-type=&quot;NumberDropDownField&quot; name=&quot;Values&quot;&gt;number drop-down fields&lt;/span&gt; and &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;text drop-down fields&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;The benefits are numerous:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Reference data table columns directly instead of manually copying values.&lt;/li&gt;
  &lt;li&gt;Create multi-level drop-downs where selecting from one field determines the
options in another.&lt;/li&gt;
  &lt;li&gt;Filter drop-down options based on text input, date ranges or other criteria.
(Like the &lt;span class=&quot;link function&quot; name=&quot;USERHASTAG&quot;&gt;role&lt;/span&gt; of the signed-in user.)&lt;/li&gt;
  &lt;li&gt;Sort options differently based on user input.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;assigning-a-formula&quot;&gt;Assigning a formula&lt;/h2&gt;

&lt;p&gt;To associate a formula with the Values property, press the new &lt;strong&gt;fx&lt;/strong&gt; button in
the inspector:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-drop-downs-values-formula/inspector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-drop-downs-values-formula/inspector.png&quot; alt=&quot;The inspector, with the fx button of drop-down field values marked&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;array-syntax&quot;&gt;Array syntax&lt;/h2&gt;

&lt;p&gt;Dynamic drop-downs use &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt; (lists of values) to provide their
options. Arrays are written between curly braces, with elements separated by
commas:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 3, 5, 7 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 3; 5; 7 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This creates a drop-down with three numeric options. For text drop-downs, use
quoted strings:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &quot;Small&quot;, &quot;Medium&quot;, &quot;Large&quot; }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &quot;Small&quot;; &quot;Medium&quot;; &quot;Large&quot; }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href=&quot;/blog/2021/11/12/array-if.html&quot;&gt;conditionally include elements&lt;/a&gt; using &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;.
If 7 should only be available when &lt;em&gt;Field1&lt;/em&gt; is valid, use this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 3, 5, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;, 7) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 3; 5; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;; 7) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;When &lt;em&gt;Field1&lt;/em&gt; is invalid, the drop-down shows only “3” and “5”. When valid, all
three options appear.&lt;/p&gt;

&lt;p&gt;To use the values of another drop-down, &lt;em&gt;MyDropDown&lt;/em&gt;, use this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;MyDropDown.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;MyDropDown,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;When you determine the values to use by setting them directly in the designer,
you can simply select one of them from the drop-down to determine which value is
shown initialy.&lt;/p&gt;

&lt;p&gt;That doesn’t work if you use a formula. In that case, you need to assign a
formula to the &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;InitialValue&quot;&gt;InitialValue&lt;/span&gt;
property.&lt;/p&gt;

&lt;h2 id=&quot;what-you-can-build&quot;&gt;What you can build&lt;/h2&gt;

&lt;p&gt;This enhancement enables several practical techniques. We’re launching with two
detailed tip posts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/blog/2025/10/15/drop-downs-table-values.html&quot;&gt;Tip: Populate drop-downs from data tables&lt;/a&gt;. Pull
values directly from data table columns, eliminating manual copying and
keeping everything synchronized automatically.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/blog/2025/10/15/drop-downs-multi-level.html&quot;&gt;Tip: Multi-level drop-downs&lt;/a&gt;. Create drop-downs that
adapt their options based on selections in other drop-downs, enabling
sophisticated multi-level filtering.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All next year, we’ll be publishing additional tips covering text-driven
filtering, date-based filtering, role-driven access control, dynamic sorting,
and working with initial values in formula-driven drop-downs.&lt;/p&gt;

&lt;p&gt;For a comprehensive overview of all available techniques, see the
&lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; documentation, which includes concise
explanations of the complete range of possibilities with formula-driven
drop-downs.&lt;/p&gt;

&lt;p&gt;We have also improved the performance of drop-down fields. While we don’t
suggest that you put thousands of options in a drop-down field, Calcapp should
now be able to handle that many options.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 11:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/drop-downs-values-formula.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/drop-downs-values-formula.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Redesigned publishing workflow</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We&apos;ve redesigned the publishing workflow to prevent accidental
  overwrites and give you better control over when changes go live.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our publishing workflow has had two related problems since &lt;a href=&quot;/blog/2015/09/26/status.html&quot;&gt;the dawn of
time&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;The Publish button immediately replaced your stable, working app with whatever
you were currently working on. One misclick pushed half-finished changes to
your users without any confirmation or review.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Emailing links to your app, sharing it on social media or embedding it in your
website — all those sharing features required you to first update your
published app, overwriting it with whatever changes you were working on.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our redesigned workflow solves both problems with a simple but important change:
separating access to your published app from the act of publishing new changes.&lt;/p&gt;

&lt;p&gt;Now when you press the Publish button, you see this dialog that gives you
choices instead of immediately overwriting your app:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-publishing-workflow/publish-page-not-published.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-publishing-workflow/publish-page-not-published.png&quot; alt=&quot;Publishing an app for the first time&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the app has been published in the past, you’ll see this dialog instead:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-publishing-workflow/publish-page-published.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-publishing-workflow/publish-page-published.png&quot; alt=&quot;Publishing a previously-published app&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For previously published apps, the dialog shows when it was last published,
helping you decide whether to update or just access the current version’s
sharing features.&lt;/p&gt;

&lt;p&gt;The crucial difference: you can now get links, sharing options and embedding
code for your stable published app without touching your work-in-progress. And
when you do choose to publish updates, you’re making a deliberate choice rather
than accidentally overwriting something that works.&lt;/p&gt;

&lt;p&gt;The sharing features themselves have also improved with &lt;a href=&quot;/blog/2025/10/15/qr-code.html&quot;&gt;QR codes&lt;/a&gt; for
easier mobile access and better support for &lt;a href=&quot;/blog/2025/10/15/launch-options.html&quot;&gt;launch options&lt;/a&gt;
when generating links.&lt;/p&gt;

&lt;p&gt;This new feature finally introduces a publishing process that gives you proper
control over when your changes go live — and when they don’t.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 10:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/publishing-workflow.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/publishing-workflow.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Launch options</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Build a single app that adapts to different contexts, including the host
  page for embedded apps. Launch options are accessible from formulas.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;You’ve built a loan calculator that your clients love. Then they ask:
“Can you make one for our mortgage division? Different rates, our
logo, our colors?” So you duplicate the app and customize it.&lt;/p&gt;

&lt;p&gt;Then the car loan team reaches out, making the same request. More
duplication. Then the business loan department. Soon you’re
maintaining four identical apps that differ only in branding and a few
parameters.&lt;/p&gt;

&lt;p&gt;Every bug fix needs to be applied four times. Every improvement gets
rolled out four times. Every formula update requires four separate
edits. You’ve multiplied your maintenance burden by the number of
variations you support.&lt;/p&gt;

&lt;p&gt;This multiplication problem affects anyone building apps for multiple
contexts: consultants serving different clients, companies with
multiple divisions, agencies creating branded calculators for various
websites.&lt;/p&gt;

&lt;p&gt;Launch options eliminate this duplication entirely and are available
today.&lt;/p&gt;

&lt;p&gt;This feature is only available in our White Label plans &lt;a href=&quot;/blog/2023/08/11/plans.html&quot;&gt;introduced in
2023&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;how-launch-options-work&quot;&gt;How launch options work&lt;/h2&gt;

&lt;p&gt;Launch options are values passed to your app through its address.
Instead of building separate apps, you build one app that reads these
values and adapts accordingly.&lt;/p&gt;

&lt;p&gt;Here’s a standard app address:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect.calcapp.net/?app=abc123&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here’s the same app with launch options:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect.calcapp.net/?app=abc123#Client=MortgageCorp&amp;amp;InterestRate=3.5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now your single app can display MortgageCorp’s branding and use their
specific interest rate — all without touching the core app.&lt;/p&gt;

&lt;p&gt;Different clients get different addresses pointing to the same underlying app:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Mortgage division: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#Client=MortgageCorp&amp;amp;InterestRate=3.5&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Auto loans: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#Client=AutoLoans&amp;amp;InterestRate=4.2&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Business credit: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#Client=BusinessCredit&amp;amp;InterestRate=6.1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One app, unlimited variations. When you fix a bug or add a feature,
every variation benefits immediately.&lt;/p&gt;

&lt;h2 id=&quot;defining-launch-options&quot;&gt;Defining launch options&lt;/h2&gt;

&lt;p&gt;When you open your app in Calcapp Creator, you’ll notice that there’s
a new section in the inspector:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-launch-options/inspector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-launch-options/inspector.png&quot; alt=&quot;Setting launch codes in the inspector&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add your first launch option, simply start typing a name (no
spaces). To add another one, start typing in the newly-revealed empty
space.&lt;/p&gt;

&lt;p&gt;Launch options are either numbers, text strings or logical values
(TRUE or FALSE). That matters when you use them in formulas — you
won’t be able to apply &lt;span class=&quot;link function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt; to a text string, for example.&lt;/p&gt;

&lt;h2 id=&quot;setting-launch-option-values&quot;&gt;Setting launch option values&lt;/h2&gt;

&lt;p&gt;When you publish an app that uses launch options (using the &lt;strong&gt;Publish
app&lt;/strong&gt; button), you’ll see a new step for setting launch option values:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-launch-options/publish.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-launch-options/publish.png&quot; alt=&quot;Setting launch codes in the inspector&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you proceed to the next step, your launch option values are part
of your app’s address.&lt;/p&gt;

&lt;p&gt;If you like, you can also set launch options just by changing the
address manually. However, note that text strings in particular
&lt;a href=&quot;https://en.wikipedia.org/wiki/Percent-encoding&quot;&gt;can be
tricky&lt;/a&gt;. Having Creator create your app links for you, including
launch parameter values, is the safer choice.&lt;/p&gt;

&lt;h2 id=&quot;using-launch-options-from-formulas&quot;&gt;Using launch options from formulas&lt;/h2&gt;

&lt;p&gt;As you have no doubt seen from the screenshots above, use
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;LaunchOptions&quot;&gt;LaunchOptions&lt;/span&gt; to access the values you have set
for your launch options:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;App.LaunchOptions!InterestRate&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;App,LaunchOptions!InterestRate&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;App.LaunchOptions!Client&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;App,LaunchOptions!Client&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Most of Calcapp’s many properties can set be through formulas, which can
now take launch options into account.&lt;/p&gt;

&lt;p&gt;What if you want a logo to be visible only if the client is Contoso?
Add a new text box for the logo and use this formula  with its
&lt;span class=&quot;link property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;App.LaunchOptions!Client &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Contoso&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;App,LaunchOptions!Client &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Contoso&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;What if you want the colors of your app to match the brand colors of
your client? Associate a formula like the following with properties like
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;BackgroundColor&quot;&gt;BackgroundColor&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;PrimaryColor&quot;&gt;PrimaryColor&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;AccentColor&quot;&gt;AccentColor&lt;/span&gt; on your first screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(App.LaunchOptions!Client, &quot;Contoso&quot;, &lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#fa43ae&quot;), &quot;Acme&quot;, &lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#bb23ca&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(App,LaunchOptions!Client; &quot;Contoso&quot;; &lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#fa43ae&quot;); &quot;Acme&quot;; &lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#bb23ca&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Launch options pair perfectly with the new &lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;FirstScreen&quot;&gt;FirstScreen&lt;/span&gt;
property of an app. Read the &lt;a href=&quot;/blog/2025/10/15/first-screen.html&quot;&gt;announcement post&lt;/a&gt; for an example.&lt;/p&gt;

&lt;h2 id=&quot;the-end-of-app-multiplication&quot;&gt;The end of app multiplication&lt;/h2&gt;

&lt;p&gt;Launch options transform how you think about building apps for multiple
contexts. Instead of asking “How many copies do I need?” you ask “What
should vary between contexts?”&lt;/p&gt;

&lt;p&gt;That loan calculator that started as four separate apps? Now it’s one
app with launch options for client branding, interest rates and loan
types. One app to maintain. One place to fix bugs. One location for
improvements.&lt;/p&gt;

&lt;p&gt;Whether you’re a consultant serving multiple clients, a company with
various divisions or an agency building branded calculators, launch
options let you scale your apps without multiplying your workload.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 09:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/launch-options.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/launch-options.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Customize the first screen shown</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Control which screen users see first based on user roles, launch options or
  saved field values. This is also a great opportunity to hide data tables and
  calculations.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Most apps show the same first screen to every user. But what if different users
need different starting points? What if employees should see a dashboard while
contractors see a welcome screen? What if your app could adapt its entry point
based on context?&lt;/p&gt;

&lt;p&gt;The new &lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;FirstScreen&quot;&gt;FirstScreen&lt;/span&gt; property lets you control exactly which
screen users see when they open your app. You can set it to a specific screen or
use a formula to make it dynamic, creating personalized experiences that adapt
to user roles, &lt;a href=&quot;/blog/2025/10/15/launch-options.html&quot;&gt;launch options&lt;/a&gt; or any other logic in your app.&lt;/p&gt;

&lt;p&gt;It’s important to note that users can’t “go back” from the first screen you set.
If you have defined several screens that come before that first screen in
Creator, those are not accessible by pressing &lt;strong&gt;Back&lt;/strong&gt; in the app. However, you
can use a go forward button to let users reach those screens.&lt;/p&gt;

&lt;h2 id=&quot;setting-the-first-screen&quot;&gt;Setting the first screen&lt;/h2&gt;

&lt;p&gt;You’ll find the new property in the inspector when you first open your app in
Creator:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-first-screen/inspector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-first-screen/inspector.png&quot; alt=&quot;Setting the first screen in the inspector&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you open the drop-down menu, you’ll find a list of all the screens in your
app, allowing you to select a different one. Use a formula to determine the
first screen by pressing the &lt;strong&gt;fx&lt;/strong&gt; button.&lt;/p&gt;

&lt;h2 id=&quot;using-with-launch-options&quot;&gt;Using with launch options&lt;/h2&gt;

&lt;p&gt;Our new &lt;a href=&quot;/blog/2025/10/15/launch-options.html&quot;&gt;launch option feature&lt;/a&gt; enables apps to adapt
depending on their context through the addresses used to launch them.&lt;/p&gt;

&lt;p&gt;Let’s assume that the launch option &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Client&lt;/code&gt; is set and the app is
launched through this address:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect.calcapp.net/?app=abc123#Client=MortgageCorp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can then associate a formula like the following with
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;FirstScreen&quot;&gt;FirstScreen&lt;/span&gt; to select a special first screen if
the client is “MortgageCorp”:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(App.LaunchOptions!Client &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;MortgageCorp&quot;, MortgageCorpScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(App,LaunchOptions!Client &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;MortgageCorp&quot;; MortgageCorpScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;With launch options, a single app can essentially masquerade as many different
apps, just by modifying the app address.&lt;/p&gt;

&lt;h2 id=&quot;hiding-your-back-end&quot;&gt;Hiding your back end&lt;/h2&gt;

&lt;p&gt;Over the years, we have added features that let you add logic and data tables to
your app that form its “back end,” things that your users interact with only
indirectly and never see as part of your user interface.&lt;/p&gt;

&lt;p&gt;Hidden fields, &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named values&lt;/a&gt; and &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data tables&lt;/a&gt;
normally need to be hidden away, and having them as part of your regular
form screens only serves to clutter them in Calcapp Creator.&lt;/p&gt;

&lt;p&gt;Traditionally, this problem has been solved in one of two ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;In apps with list screens, you can place a navigator at the bottom and make
it &lt;span class=&quot;link property&quot; parent-type=&quot;Navigator&quot; name=&quot;Visible&quot;&gt;hidden&lt;/span&gt;. Under this navigator, you put
all the background elements. Sometimes this requires another list screen to
organize everything, sometimes a single form screen suffices.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In apps without list screens, you put background screens at the end, then
set &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt; to FALSE on the last
user-facing screen to prevent users from going further. The downside is a
grayed-out &lt;strong&gt;Next&lt;/strong&gt; button in your app.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The FirstScreen property offers a cleaner solution: put all background logic
at the beginning of your app, then use FirstScreen to jump directly to the
screen users should see. Your app stays organized without workarounds.&lt;/p&gt;

&lt;h2 id=&quot;user-based-personalization&quot;&gt;User-based personalization&lt;/h2&gt;

&lt;p&gt;Beyond app organization and launch options, FirstScreen enables personalization
based on who’s using your app.&lt;/p&gt;

&lt;h3 id=&quot;role-based-access&quot;&gt;Role-based access&lt;/h3&gt;

&lt;p&gt;For &lt;a href=&quot;/blog/2019/04/12/private-apps.html&quot;&gt;private apps&lt;/a&gt;, use &lt;span class=&quot;link function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt; to
show different first screens based on user tags. This formula presents
different screens for employees versus contractors:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt;(&quot;Employee&quot;), EmployeeScreen, &lt;span class=&quot;function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt;(&quot;Contractor&quot;), ContractorScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt;(&quot;Employee&quot;); EmployeeScreen; &lt;span class=&quot;function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt;(&quot;Contractor&quot;); ContractorScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;NextScreen&lt;/span&gt; on both screens to merge users
back to a common second screen, keeping the rest of the experience unified.&lt;/p&gt;

&lt;h3 id=&quot;email-based-access&quot;&gt;Email-based access&lt;/h3&gt;

&lt;p&gt;If you don’t use tags, check the user’s email address instead:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ENDSWITH&quot;&gt;ENDSWITH&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;UserEmailAddress&quot;&gt;UserEmailAddress&lt;/span&gt;, &quot;@ourcorp.com&quot;), EmployeeScreen, ContractorScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ENDSWITH&quot;&gt;ENDSWITH&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;UserEmailAddress&quot;&gt;UserEmailAddress&lt;/span&gt;; &quot;@ourcorp.com&quot;); EmployeeScreen; ContractorScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This shows &lt;em&gt;EmployeeScreen&lt;/em&gt; for company email addresses and &lt;em&gt;ContractorScreen&lt;/em&gt;
for everyone else.&lt;/p&gt;

&lt;h2 id=&quot;using-saved-field-values&quot;&gt;Using saved field values&lt;/h2&gt;

&lt;p&gt;As &lt;a href=&quot;/blog/2016/11/19/persistent-fields.html&quot;&gt;fields can remember their values&lt;/a&gt; between
sessions, you can check previous user input to determine the
appropriate starting screen based on their history with your app.&lt;/p&gt;

&lt;h2 id=&quot;creating-adaptive-experiences&quot;&gt;Creating adaptive experiences&lt;/h2&gt;

&lt;p&gt;The FirstScreen property transforms apps from one-size-fits-all to
adaptive experiences. Whether you’re personalizing based on user roles,
adapting to different contexts through launch options, or simply
organizing your app’s structure better, this feature gives you the
control to ensure every user starts their journey at exactly the right
place.&lt;/p&gt;

&lt;p&gt;Combined with formulas, FirstScreen becomes a powerful tool for creating
sophisticated app experiences that feel tailored to each user’s needs.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 08:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/first-screen.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/first-screen.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: QR codes for your apps</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  QR codes for your apps make it easy to test and share your apps across
  devices.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;There’s a fundamental mismatch in how we build and consume apps: most
people develop on desktop computers but primarily use apps on their
phones. This creates a friction point every time you want to test your
latest changes or share your app with others.&lt;/p&gt;

&lt;p&gt;Traditional solutions require typing long addresses, sending yourself
emails or dealing with complex sharing workflows. But there’s a better
way.&lt;/p&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2025/10/15/publishing-workflow.html&quot;&gt;redesigned publishing workflow&lt;/a&gt; includes QR
code support that solves this desktop-to-mobile handoff problem
elegantly:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-qr-code/link-tab.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-qr-code/link-tab.png&quot; alt=&quot;Support for QR codes&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Point any modern smartphone camera at the QR code, and your app opens
instantly. No typing, no fumbling with addresses, no friction. If you
hover over the QR code, a download button appears, allowing you to
download a high-resolution version for your own use.&lt;/p&gt;

&lt;p&gt;This capability transforms several important workflows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Instant testing&lt;/strong&gt;: Build on desktop, test on mobile immediately.
Instead of typing addresses or sending yourself emails, just point your
phone at the screen. (For draft versions, you can always use
&lt;a href=&quot;https://connect.calcapp.net&quot; target=&quot;connect&quot;&gt;connect.calcapp.net&lt;/a&gt;
to open works-in-progress directly.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Professional sharing&lt;/strong&gt;: Use the high-resolution QR codes for
business cards, flyers, websites and ads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility&lt;/strong&gt;: Eliminate typing barriers entirely. QR codes work
for users who struggle with complex addresses or small phone keyboards.&lt;/p&gt;

&lt;p&gt;QR codes became mainstream during the pandemic as everyone learned to
scan codes for menus, payments and information. We’re building on that
familiarity to help you get your creations from the development
environment to users’ hands as smoothly as possible.&lt;/p&gt;

&lt;p&gt;PS. Did you know that QR codes were invented in Japan in the 1990s to
track automobile parts and have special support for Japanese
characters (Kanji)? “QR” stands for “quick response.” The inventors
made the technology freely available to encourage widespread adoption.
&lt;a href=&quot;https://en.wikipedia.org/wiki/QR_code&quot;&gt;Wikipedia has other fun facts.&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 07:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/qr-code.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/qr-code.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Bulgarian language support</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Thanks to a user in Bulgaria, we now support 31 fully translated
  languages, making Calcapp accessible to an even broader global audience.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Thanks to an intrepid user in Bulgaria, Calcapp now supports Bulgarian as its
31st fully translated language. This means Bulgarian-language apps now display
proper text labels like &lt;em&gt;Back&lt;/em&gt; (to move back to the previous screen) and &lt;em&gt;Open&lt;/em&gt;
(to open a downloaded report), in addition to the number and date formatting
that Calcapp has supported for years.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want your language fully supported?&lt;/strong&gt; &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;Get in touch&lt;/a&gt; and we’ll
work with you to make it happen.&lt;/p&gt;

&lt;p&gt;Since &lt;a href=&quot;/blog/2018/03/06/locales.html&quot;&gt;we introduced multilingual support seven years ago&lt;/a&gt;, Calcapp has
supported 79 languages and 147 language variants for number and date formatting.
For example, 123,456.78 in US English is rendered as “123 456,78” in Swedish,
and “October 24, 2043” is rendered as “24 oktober, 2043” in Swedish. However,
only a subset of these languages have full translations for app interface
labels.&lt;/p&gt;

&lt;h2 id=&quot;why-language-support-matters&quot;&gt;Why language support matters&lt;/h2&gt;

&lt;p&gt;Out of curiosity, we analyzed what languages our published apps use. When we
look only at apps created by paying customers, English accounts for less than
half of all published apps. More than half of our customer base creates apps in
other languages.&lt;/p&gt;

&lt;p&gt;This suggests that multilingual support isn’t just a nice feature — it’s
essential. Without it, we likely would have lost more than half of our customers
to competitors. The investment in language support has clearly paid off.&lt;/p&gt;

&lt;p&gt;Here’s the breakdown of all published apps (including test apps from trial
users, which explains English’s dominance as the default):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2025-10-15-bulgarian/languages.svg&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2025-10-15-bulgarian/languages.svg&quot; alt=&quot;The languages used by our published apps&quot; class=&quot;large-image no-shadow&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beyond adding Bulgarian, we’ve also improved translations for several existing
languages, ensuring that interface labels better match what native speakers
expect. These refinements make apps feel more natural and professional to users
around the world.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 06:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/bulgarian.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/bulgarian.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Bug report: Formula reliability improvements</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Numerous edge cases in formula evaluation have been resolved, making
  complex formulas more reliable and predictable.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Originally, our &lt;a href=&quot;/blog/2025/10/15/release.html&quot;&gt;latest release&lt;/a&gt; was planned for
this spring. What happened? Well, we hit a snag.&lt;/p&gt;

&lt;p&gt;When we wrote one of the blog posts describing the new
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; property of number and text
drop-down fields, the numbers in the example app we developed didn’t
update properly. Puzzled, we looked into the issue, not knowing that
we’d have to spend months reworking Calcapp to make the app work.&lt;/p&gt;

&lt;p&gt;We fixed a very similar issue &lt;a href=&quot;/blog/2024/06/13/formula-bugs.html&quot;&gt;roughly one year ago&lt;/a&gt;. The
issue then was that referencing &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named values&lt;/a&gt; through functions
like &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt; would lead to subtle bugs —
calculations wouldn’t update and we couldn’t reliably detect &lt;em&gt;cycles&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Cycles occur when formulas reference themselves, either directly or through
a chain of other properties. While this might seem obvious to avoid, it can
happen accidentally in complex apps with many interconnected formulas.&lt;/p&gt;

&lt;p&gt;The fix we introduced a year ago turned out not to fix all issues with named
values. It turned out to be a band-aid and not a long-term fix, so we had to go
back to the drawing board and do this right.&lt;/p&gt;

&lt;h2 id=&quot;what-we-fixed&quot;&gt;What we fixed&lt;/h2&gt;

&lt;p&gt;Beyond the named values issues, we found other subtle problems. For example,
consider a property like &lt;span class=&quot;link property&quot; parent-type=&quot;ResetButton&quot; name=&quot;IncludedFields&quot;&gt;IncludedFields&lt;/span&gt; of reset
buttons. A formula like the following would work in some cases but not others:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(ResetButton1.IncludedFields)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(ResetButton1,IncludedFields)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This used to work fine if that property was set with a formula, but would give
an error if you selected fields in the inspector instead. This inconsistency
has now been fixed.&lt;/p&gt;

&lt;p&gt;There are many other similar problems that have been resolved, particularly
when named values reference other named values in complex ways.&lt;/p&gt;

&lt;h2 id=&quot;our-commitment-to-formulas&quot;&gt;Our commitment to formulas&lt;/h2&gt;

&lt;p&gt;Sometimes customers ask us if Excel is running in the background on our server
to power our apps and formula editing experience. The answer is no — that
wouldn’t be practical (or legal). We use our fully custom formula engine,
which consists of hundreds of thousands of lines of code developed over 16 years.&lt;/p&gt;

&lt;p&gt;We believe Calcapp’s formulas are its best feature. They enable the flexibility
that ensures your apps meet your needs. We will continue investing to make sure
this foundational part of Calcapp remains reliable, no matter how complex your
formulas become.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 05:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/formula-bugs.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/formula-bugs.html</guid>
        
        <category>Bug report</category>
        
        
      </item>
    
      <item>
        <title>Bug report: Creator stability enhancements</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We&apos;ve fixed two annoying bugs in Calcapp Creator that were hard to
  reproduce. Formula popups now dismiss properly and multi-selection
  works reliably.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Calcapp Creator, our app designer, has been afflicted with two minor but
annoying bugs for some time now. The problem was that we couldn’t consistently
reproduce them, which made them much more challenging to fix.&lt;/p&gt;

&lt;p&gt;Fortunately, we managed to fix both for this release. These fixes, along with
several other improvements, make Calcapp Creator feel more polished and
reliable.&lt;/p&gt;

&lt;h2 id=&quot;formula-popup&quot;&gt;Formula popup&lt;/h2&gt;

&lt;p&gt;When you edit formulas, we helpfully show you where you are in a particular
function (first or second parameter to &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;?), along with
concise documentation. This feature was introduced &lt;a href=&quot;/blog/2023/08/11/better-documentation.html&quot;&gt;roughly two years
ago&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the same time, &lt;a href=&quot;/blog/2023/08/11/autocomplete.html&quot;&gt;we introduced formula autocomplete&lt;/a&gt;, which
shows you a list of suggestions for things like functions and fields you may be
trying to reference.&lt;/p&gt;

&lt;p&gt;It turned out that when both were displayed at the same time—the function
information and the autocomplete popup—moving away from the formula editor
would only dismiss the autocomplete popup, not the function information.&lt;/p&gt;

&lt;p&gt;Sure, you could press a button to dismiss that information, but this was still
annoying. What was more annoying for us was that it took a while to figure out
that this only happened when both were showing at the same time.&lt;/p&gt;

&lt;p&gt;This problem has now been fixed, making the app authoring experience much more
polished. Finally.&lt;/p&gt;

&lt;h2 id=&quot;checking-many-items&quot;&gt;Checking many items&lt;/h2&gt;

&lt;p&gt;You may not be aware, but you can speed up your workflow quite a bit by editing
multiple fields, buttons and other elements at the same time. Just press the
check mark next to all the items you want to edit, and the inspector will apply
all changes you make to all the selected items.&lt;/p&gt;

&lt;p&gt;(This feature even enables you to &lt;a href=&quot;/blog/2023/08/11/edit-multiple-formulas.html&quot;&gt;edit the formulas of multiple
properties&lt;/a&gt; at the same time!)&lt;/p&gt;

&lt;p&gt;The only problem was that this feature stopped working occasionally. You’d check
multiple items and be rewarded with an empty inspector. Not good.&lt;/p&gt;

&lt;p&gt;We encountered this problem on numerous occasions, but every time we got ready
to track down the issue, everything worked just fine.&lt;/p&gt;

&lt;p&gt;Then, a week or two later, we’d encounter the same problem again, realizing that
the pesky bug still lingered.&lt;/p&gt;

&lt;p&gt;It turned out that every time we tried to track down the issue, we started fresh
with a newly loaded Calcapp Creator, which wasn’t very effective because the
problem only manifested after you opened a new app.&lt;/p&gt;

&lt;p&gt;With the problem being fully reproducible, we were finally able to fix the bug.
Along with the popup fix mentioned above, we think this makes for a much more
polished experience.&lt;/p&gt;

&lt;h2 id=&quot;additional-polish-improvements&quot;&gt;Additional polish improvements&lt;/h2&gt;

&lt;p&gt;Beyond the two main bug fixes, we’ve addressed several other issues that
contribute to a more polished Creator experience:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;When selecting a screen from the inspector (such as the
&lt;span class=&quot;link property&quot; parent-type=&quot;GoBackButton&quot; name=&quot;Target&quot;&gt;Target&lt;/span&gt; property of go back buttons or the new
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;FirstScreen&quot;&gt;FirstScreen&lt;/span&gt; property of your app), the display could get
garbled for long screen names. Fixed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We use your location for various things, especially when displaying prices
when you make plan changes (we even translate the &lt;a href=&quot;https://en.wikipedia.org/wiki/Value-added_tax&quot;&gt;VAT term&lt;/a&gt; to 25
different languages). To do that, we subscribe to a service that tells us your
country from your IP address. This service can fail intermittently, which
makes Creator crash. We now recover from those failures more gracefully.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We’ve modernized our embedding features by dropping Internet Explorer support.
When &lt;a href=&quot;/blog/2019/07/21/embed-tab.html&quot;&gt;embedding your apps&lt;/a&gt; in a web page, you can include a
&lt;a href=&quot;/blog/2019/07/21/iframe-library.html&quot;&gt;JavaScript library&lt;/a&gt; enabling your page to communicate with
the app, realizing things such as &lt;a href=&quot;/blog/2019/07/21/auto-height.html&quot;&gt;auto-height&lt;/a&gt;. The embed tab
now reflects this change, though existing apps using our Internet Explorer
support will continue working for the time being.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While individually small, these improvements collectively make Calcapp Creator
feel more reliable. The formula popup and multi-selection fixes in particular
eliminate two of the most annoying workflow interruptions our users experienced.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 04:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/creator-bugs.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/creator-bugs.html</guid>
        
        <category>Bug report</category>
        
        
      </item>
    
      <item>
        <title>Tip: Populate drop-downs from data tables</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Pull values directly from data table columns, eliminating manual copying
  and keeping everything synchronized automatically. Changes to your data
  tables instantly reflect in all connected drop-downs.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Drop-down fields often need to display values that already exist in your data
tables — product names, categories, colors and other attributes stored in the
&lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data editor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Previously, you had to copy these values from your data table and paste them
into each drop-down field. Worse, whenever you updated the data table, you had
to remember to manually update every affected drop-down field. This created
maintenance headaches and opportunities for things to get out of sync.&lt;/p&gt;

&lt;p&gt;Now that drop-down field values can be defined &lt;a href=&quot;/blog/2025/10/15/drop-downs-values-formula.html&quot;&gt;using
formulas&lt;/a&gt;, there’s a better way: pull values directly
from your data tables. Update the table once, and every drop-down field reflects
the change automatically.&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;

&lt;p&gt;Imagine you have the following data table of products:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Name&lt;/th&gt;
      &lt;th&gt;Kind&lt;/th&gt;
      &lt;th&gt;Size&lt;/th&gt;
      &lt;th&gt;Color&lt;/th&gt;
      &lt;th&gt;Price&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;

  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Ocean Breeze Knit&lt;/td&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Blue&lt;/td&gt;
      &lt;td&gt;29&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Deep Blue Comfort&lt;/td&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Blue&lt;/td&gt;
      &lt;td&gt;49&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Royal Glow Pullover&lt;/td&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Purple&lt;/td&gt;
      &lt;td&gt;39&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Violet Cozy Wrap&lt;/td&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Small&lt;/td&gt;
      &lt;td&gt;Purple&lt;/td&gt;
      &lt;td&gt;29&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Moonlight Shift&lt;/td&gt;
      &lt;td&gt;Dress&lt;/td&gt;
      &lt;td&gt;Small&lt;/td&gt;
      &lt;td&gt;Gray&lt;/td&gt;
      &lt;td&gt;69&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Midnight Elegance&lt;/td&gt;
      &lt;td&gt;Dress&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Black&lt;/td&gt;
      &lt;td&gt;129&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Sapphire Flow&lt;/td&gt;
      &lt;td&gt;Dress&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Blue&lt;/td&gt;
      &lt;td&gt;72&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Shadow Flex Shorts&lt;/td&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Black&lt;/td&gt;
      &lt;td&gt;39&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Onyx Sport Shorts&lt;/td&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Black&lt;/td&gt;
      &lt;td&gt;52&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Ash Drift Shorts&lt;/td&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Gray&lt;/td&gt;
      &lt;td&gt;49&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Mystic Air Shorts&lt;/td&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Purple&lt;/td&gt;
      &lt;td&gt;19&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Create a form screen called &lt;em&gt;Products&lt;/em&gt; and use the data editor to create one
&lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named value&lt;/a&gt; for each column. The product names become accessible
as the &lt;em&gt;Name&lt;/em&gt; named value, colors as the &lt;em&gt;Color&lt;/em&gt; named value, and so on.&lt;/p&gt;

&lt;p&gt;To create a drop-down field that lets users select a product, assign this
formula to its &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Products!Name&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Products!Name&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;That’s it. The drop-down now displays all product names from the table.&lt;/p&gt;

&lt;h2 id=&quot;handling-duplicates&quot;&gt;Handling duplicates&lt;/h2&gt;

&lt;p&gt;What if you want users to select a color? This formula works, but creates a
problem:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Products!Color&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Products!Color&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;While there are only four unique colors (blue, purple, gray and black), the
drop-down displays eleven entries — one for every product — with many
duplicates.&lt;/p&gt;

&lt;p&gt;Remove duplicates using the &lt;span class=&quot;link function&quot; name=&quot;UNIQUE&quot;&gt;UNIQUE&lt;/span&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;UNIQUE&quot;&gt;UNIQUE&lt;/span&gt;(Products!Color)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;UNIQUE&quot;&gt;UNIQUE&lt;/span&gt;(Products!Color)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;For alphabetical order, add the &lt;span class=&quot;link function&quot; name=&quot;SORT&quot;&gt;SORT&lt;/span&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SORT&quot;&gt;SORT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;UNIQUE&quot;&gt;UNIQUE&lt;/span&gt;(Products!Color))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SORT&quot;&gt;SORT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;UNIQUE&quot;&gt;UNIQUE&lt;/span&gt;(Products!Color))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Now your drop-down shows each color exactly once, sorted alphabetically.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This technique requires named values and the data editor, which are
not available in our Starter plans.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 03:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/drop-downs-table-values.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/drop-downs-table-values.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Multi-level drop-downs</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Create drop-downs that adapt their options based on selections in other
  drop-downs. Perfect for country/state selections, category/product
  filtering, and other hierarchical data relationships.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Multi-level%20drop-downs
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Multi-level drop-downs are a common pattern: select a country, then choose from
states or provinces specific to that country. Select a category, then pick from
products in that category. The second drop-down adapts based on the first
selection.&lt;/p&gt;

&lt;p&gt;Previously, this required complex workarounds involving multiple hidden
drop-down fields that appeared and disappeared based on the first selection.
Now that the &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; property can be set using
formulas that return &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt;, multi-level drop-downs are
straightforward to implement.&lt;/p&gt;

&lt;h2 id=&quot;example-north-american-regions&quot;&gt;Example: North American regions&lt;/h2&gt;

&lt;p&gt;Here’s an app that lets users select a country in North America. The state or
province drop-down adapts its values based on the country selection:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 110px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=9ykv7e&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;The app uses three &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named values&lt;/a&gt;: &lt;em&gt;UsStates&lt;/em&gt;, &lt;em&gt;MexicanStates&lt;/em&gt;
and &lt;em&gt;CanadianStatesTerritories&lt;/em&gt;. Here’s the start of the &lt;em&gt;UsStates&lt;/em&gt; value:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &quot;Alabama&quot;, &quot;Alaska&quot;, &quot;Arizona&quot;, … }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &quot;Alabama&quot;; &quot;Alaska&quot;; &quot;Arizona&quot;; … }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt; property of the state/province
drop-down uses this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(Country, &quot;Canada&quot;, CanadianStatesTerritories, &quot;United States&quot;, UsStates, &quot;Mexico&quot;, MexicanStates)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(Country; &quot;Canada&quot;; CanadianStatesTerritories; &quot;United States&quot;; UsStates; &quot;Mexico&quot;; MexicanStates)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This uses the &lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt; function, but &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; work equally well.&lt;/p&gt;

&lt;h2 id=&quot;dynamic-labels&quot;&gt;Dynamic labels&lt;/h2&gt;

&lt;p&gt;Canadian provinces are either &lt;em&gt;states&lt;/em&gt; or &lt;em&gt;territories&lt;/em&gt;. The drop-down label
reflects this using a formula for the &lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;
property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(Country, &quot;Canada&quot;, &quot;State or territory&quot;, &quot;State&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(Country; &quot;Canada&quot;; &quot;State or territory&quot;; &quot;State&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;selecting-a-default-value&quot;&gt;Selecting a default value&lt;/h2&gt;

&lt;p&gt;Drop-downs with formula-based values don’t have a default selection. When the
country changes, no state or province is initially selected.&lt;/p&gt;

&lt;p&gt;To automatically select the first option, assign this formula to the
&lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;InitialValue&quot;&gt;InitialValue&lt;/span&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;, 1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Item,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;; 1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;/blog/2023/08/11/grab-bag.html#access-the-current-item-from-a-formula&quot;&gt;Item&lt;/a&gt; formula parameter accesses the current drop-down field,
letting you reference its Values property. (You could also write
&lt;span class=&quot;formula decimalpoint&quot;&gt;State.&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;State,&lt;span class=&quot;property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Values&quot;&gt;Values&lt;/span&gt;&lt;/span&gt; to reference the field by name.)&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This technique requires named values, which are not available in our
Starter plans. You can work around this by directly embedding the array formulas
instead of using named value references.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 02:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/drop-downs-multi-level.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/drop-downs-multi-level.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Revised learning guides</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We&apos;ve overhauled our learning guides with clearer headlines, bullet points
  instead of prose and more concise explanations to make them easier to scan.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;We’ve given our &lt;a href=&quot;/learn/&quot;&gt;learning guides&lt;/a&gt; a comprehensive overhaul to make them
easier to follow and more effective for users at all levels.&lt;/p&gt;

&lt;p&gt;The main improvements include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Clearer headlines&lt;/strong&gt; that help you find exactly what you’re looking for.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Bullet points instead of dense prose&lt;/strong&gt; to make scanning and finding
information faster.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;More concise explanations&lt;/strong&gt; that get to the point without sacrificing
clarity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As Calcapp continues to grow with new features and capabilities, our goal is
to provide a comprehensive yet accessible overview of the entire platform. We
want the guides to give you a thorough understanding without becoming a lengthy
read.&lt;/p&gt;

&lt;p&gt;To achieve this, we’ve actually added new material covering the recent features,
while managing to reduce the word count (from roughly 32,000 words to 27,000
words, a 16 percent reduction). This means you can quickly get up to speed on
everything Calcapp offers, from basic app building to advanced formula
techniques.&lt;/p&gt;

&lt;p&gt;Whether you’re new to Calcapp or looking to explore features you haven’t used
yet, the updated guides should provide a much smoother learning experience.&lt;/p&gt;

&lt;p&gt;If you haven’t read the guides in a couple of years, now is a great time to
dive in and scan them to see if there’s anything you’ve missed!&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 01:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/revised-guides.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/revised-guides.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Our tip demo apps are now available as templates</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Eight tip blog posts with demo apps now have template versions you can
  open directly in Calcapp Creator, making advanced techniques easier to learn.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Since 2017, we have published 39 tip blog posts — informative articles
covering interesting techniques you can use in your own apps. Eight of these
posts include live app demos to illustrate the techniques in action.&lt;/p&gt;

&lt;p&gt;Until now, you couldn’t work with those demo apps in Calcapp Creator. We
recognize that being able to study and modify these examples is valuable for
learning, so starting today, those eight tip posts now include a link that
creates a new app in Creator based on the demo app.&lt;/p&gt;

&lt;p&gt;When you create a new app in Creator, you’ll also find these tip templates
available alongside the standard sample apps and Blank template option.&lt;/p&gt;

&lt;p&gt;Here are the tip posts now available as templates:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2025/10/15/drop-downs-multi-level.html&quot;&gt;Multi-level drop-downs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2024/10/15/selectable-products.html&quot;&gt;Display only selected screens&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2024/08/06/switch-fields.html&quot;&gt;Determine the number of toggled switch fields&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2023/08/11/calculation-buttons.html&quot;&gt;Perform calculations when a button is pressed&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2023/08/11/required-button.html&quot;&gt;Require a button to be pressed&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2023/02/05/conditional-images.html&quot;&gt;Decide which image to show with a formula&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2022/06/02/text-summary.html&quot;&gt;Summarize switch field selections in a single sentence&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2022/04/18/holidays.html&quot;&gt;Display all US legal holidays for a given year&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These templates make it easier to understand advanced techniques and adapt them
for your own projects. Simply open any tip post and look for the template link
to get started.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Now all our &lt;a href=&quot;/blog/tag/sample-app.html&quot;&gt;sample app posts&lt;/a&gt; also come with these
convenient links.&lt;/p&gt;

</description>
        <pubDate>Wed, 15 Oct 2025 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/10/15/tip-templates.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/10/15/tip-templates.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>A new release is coming</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We&apos;re preparing a new release with formula-powered drop-down values and other
  exciting new features. Behind the scenes, we&apos;ve also been modernizing Calcapp
  for the future.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;The first thing we do when evaluating a new service is to check out the blog, as
we don’t want to invest time and money in a service that isn’t being actively
developed or supported. In our experience, a well-maintained service usually
goes hand in hand with a well-maintained blog.&lt;/p&gt;

&lt;p&gt;By that metric, we have let you down recently. With only one blog entry posted
this year, it may seem like Calcapp is dormant.&lt;/p&gt;

&lt;p&gt;Thankfully, nothing could be further from the truth — we’re moving full-speed
ahead with a new release. While smaller in scope than some of our previous ones,
this release is packed with important new features that will enable entirely new
kinds of apps.&lt;/p&gt;

&lt;p&gt;We’ll keep some of features under wraps for now, but the headline addition is
this: you will be able to set the values of drop-down fields using formulas.
That single change unlocks a wealth of possibilities, including:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Populate drop-downs from data tables.&lt;/strong&gt; Link drop-down fields directly to a
column in a data table — no more copying and pasting values.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Multi-level drop-downs.&lt;/strong&gt; Use one drop-down field to determine the values
displayed in another.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Text-driven drop-down filtering.&lt;/strong&gt; Allow your users to filter a drop-down
field using a text field.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Filter drop-downs with switch fields.&lt;/strong&gt; Use switch fields to refine the
available drop-down values.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Filter drop-downs using dates.&lt;/strong&gt; Filter drop-down values based on start and
end dates selected in date and time fields.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Filter drop-downs using user roles.&lt;/strong&gt; &lt;a href=&quot;/blog/2019/04/12/private-apps.html&quot;&gt;Private apps&lt;/a&gt; require
users to sign in. If a role is assigned to a user, you can use that role to
filter what’s shown in a drop-down.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Custom sort order.&lt;/strong&gt; For drop-downs with many values, order matters.
Customize the sort order to make options easier to scan.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This new feature places significant demands on our formula engine. In fact,
while writing one of the upcoming blog posts about these features, we uncovered
several issues.&lt;/p&gt;

&lt;p&gt;The culprits? &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;Named values&lt;/a&gt;, which we’ve come to rely on heavily
when building apps. Under stress, they didn’t always behave correctly —
surfacing issues similar to the ones we &lt;a href=&quot;/blog/2024/06/13/formula-bugs.html&quot;&gt;identified and fixed last
year&lt;/a&gt;. We’ve spent the past few months diving deep into these
problems, and we’re now nearing the finish line.&lt;/p&gt;

&lt;p&gt;Since our &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;last major release&lt;/a&gt; nearly two years ago, most
of our time has actually gone into a far-reaching project to modernize Calcapp
and prepare it for the future. Specifically, we’re working to make it easy to
use our formula engine in new contexts.&lt;/p&gt;

&lt;p&gt;That work will have exciting implications down the line — we look forward to
sharing more when it’s ready.&lt;/p&gt;

&lt;p&gt;In the meantime, we’re thrilled about our upcoming release, which should be
ready in the coming months.&lt;/p&gt;

</description>
        <pubDate>Tue, 29 Jul 2025 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/07/29/upcoming-release.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/07/29/upcoming-release.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Our most popular formula functions</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Which of our many formula functions are used the most? This post lists the 50
  most popular functions.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;It’s the start of a brand new year, and we thought it would be fun to kick
things off by sharing a look at what &lt;a href=&quot;/learn/formulas/&quot;&gt;functions&lt;/a&gt; you’re using the most
in Calcapp!&lt;/p&gt;

&lt;p&gt;The list holds some interesting surprises — while it’s no shock that the
&lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; function takes the top spot with over a million uses, we
didn’t expect to see the financial function &lt;span class=&quot;link function&quot; name=&quot;CUMPRINC&quot;&gt;CUMPRINC&lt;/span&gt; coming in
as the second most popular.&lt;/p&gt;

&lt;p&gt;Without further ado, these are the 50 most popular functions:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Function name&lt;/th&gt;
    &lt;th&gt;Usage count&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,124,124&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;CUMPRINC&quot;&gt;CUMPRINC&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;249,885&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;232,818&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ROUND&quot;&gt;ROUND&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;208,927&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;182,306&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;122,643&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;113,207&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;63,443&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;TONUMBER&quot;&gt;TONUMBER&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;37,785&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;25,618&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;FV&quot;&gt;FV&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;20,373&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;MIN&quot;&gt;MIN&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;20,099&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;15,895&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;LEN&quot;&gt;LEN&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;15,465&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;13,757&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;IFERROR&quot;&gt;IFERROR&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;10,897&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;10,298&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ISERROR&quot;&gt;ISERROR&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;9,264&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;FIND&quot;&gt;FIND&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;9,209&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;CEILING&quot;&gt;CEILING&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;7,797&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;7,687&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;FORMATPERCENTAGE&quot;&gt;FORMATPERCENTAGE&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;7,455&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;5,931&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ISBLANK&quot;&gt;ISBLANK&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;5,035&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;MROUND&quot;&gt;MROUND&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;4,605&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;REGEXREPLACE&quot;&gt;REGEXREPLACE&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;4,498&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ROUNDUP&quot;&gt;ROUNDUP&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;4,332&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;4,139&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;CONVERT&quot;&gt;CONVERT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;3,755&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;FLOOR&quot;&gt;FLOOR&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;3,638&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;SUBSTITUTE&quot;&gt;SUBSTITUTE&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;3,595&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;RANDBETWEEN&quot;&gt;RANDBETWEEN&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;3,212&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;SQRT&quot;&gt;SQRT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;2,762&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;MOD&quot;&gt;MOD&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;2,545&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;2,532&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;RADIANS&quot;&gt;RADIANS&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;2,263&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;HSB&quot;&gt;HSB&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;2,172&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;PMT&quot;&gt;PMT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,928&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,915&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;TOTEXT&quot;&gt;TOTEXT&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,893&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;ROUNDDOWN&quot;&gt;ROUNDDOWN&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,863&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;NOW&quot;&gt;NOW&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,857&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;COS&quot;&gt;COS&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,772&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,351&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;HSL&quot;&gt;HSL&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,293&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;CONCATENATE&quot;&gt;CONCATENATE&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,214&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,163&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,155&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;&lt;span class=&quot;link function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;&lt;/td&gt;
    &lt;td&gt;1,150&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;The ten most popular functions are now displayed permanently on the first
&lt;a href=&quot;/learn/formulas/&quot;&gt;formula reference page&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Thu, 09 Jan 2025 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2025/01/09/popular-functions.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2025/01/09/popular-functions.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Looking ahead</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Calcapp is evolving! Exciting updates are on the horizon, including enhanced
  web integration, data handling and AI features.
&lt;/div&gt;

&lt;p&gt;As 2024 draws to a close, we wanted to take a moment to give you an update on
what’s going on with Calcapp.&lt;/p&gt;

&lt;p&gt;First and foremost, thanks for being a part of our community and for trusting us
as a valued customer. It’s because of you that we’re able to keep improving
Calcapp. There are many exciting new features on the horizon that will improve
your workflow and make the apps you build even better.&lt;/p&gt;

&lt;h2 id=&quot;supporting-you-when-youre-building-your-apps&quot;&gt;Supporting you when you’re building your apps&lt;/h2&gt;

&lt;p&gt;Every &lt;a href=&quot;/pricing/&quot;&gt;plan&lt;/a&gt; we offer includes support. That means if you ever find
yourself stuck, we’re just an email or a chat message away. (While our chat
system isn’t staffed 24/7, we’ll get back to you as soon as possible during
office hours in Western Europe.)&lt;/p&gt;

&lt;p&gt;However, if you want us to fully build an app for you, we offer that as part of
our professional services program. As the world’s foremost Calcapp experts,
we’re able to build apps for you that use all the bells and whistles of the
platform, and we’re likely able to do so faster and more cost-efficiently than
your own team, which would need time to get up to speed first.&lt;/p&gt;

&lt;p&gt;Some customers want us to build apps and maintain them for them, while others
just want us to create the beginnings of an app, enabling them to take the reins
once the groundwork has been laid.&lt;/p&gt;

&lt;p&gt;Both approaches are equally valid. &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;Reach out to us&lt;/a&gt; and we’ll be
happy to discuss your requirements in detail.&lt;/p&gt;

&lt;h2 id=&quot;building-the-future&quot;&gt;Building the future&lt;/h2&gt;

&lt;p&gt;Behing the scenes, we’re laying the foundation for the next chapter of Calcapp.
Our vision is to make Calcapp more versatile, powerful, and user-friendly. We’re
exploring new features that will enable smoother web integration and more robust
data handling, which we know are major goals for many of you. We’re also excited
about the potential of integrating AI into Calcapp to streamline workflows,
offer smart suggestions and make app building even more intuitive.&lt;/p&gt;

&lt;p&gt;These projects are foundational, and while it will take time before they’re
ready for release, we are deeply committed to this vision. It’s thrilling to
think of where Calcapp will go from here. We’re excited to shape this future
together and promise to keep you updated as our work progresses.&lt;/p&gt;

&lt;p&gt;We couldn’t do any of this without you. Your trust, enthusiasm and financial
support allow us to push boundaries and dream big for Calcapp. We can’t wait to
share more about what’s coming next.&lt;/p&gt;

</description>
        <pubDate>Tue, 12 Nov 2024 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2024/11/12/update.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2024/11/12/update.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Tip: Display only selected screens</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  If you have an app for a large product catalog, with screens for every
  product, having a large list screen leading to all products may not be
  practical. This tip explores an alternative.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Display%20only%20selected%20screens
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Many of our clients create apps for their product catalog. A straight-forward
way of modeling this in an app is to use a list screen, containing all products,
and then have form screens associated with every list screen navigator, holding
the product calculations.&lt;/p&gt;

&lt;p&gt;For the client project we’re currently working on, our client wanted a different
approach. Having the users of the app go back and forth between individual form
screens and the list screen containing all products would be too slow. Instead,
our client wanted the users of the app to be asked which products they intended
to use, and then have the app present screens for those exact products, and only
those products.&lt;/p&gt;

&lt;p&gt;Here’s an app demonstrating this technique:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 680px; width: 100%; max-width: 540px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=7zrs16&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;The first screen is a form screen, not a list screen. It has one switch field
for every product. The user is required to toggle at least one of these switch
fields to its “on” position. Once that is done, the user may proceed to the next
screen by pressing &lt;strong&gt;Next&lt;/strong&gt; in the upper-right corner or by pressing the
&lt;strong&gt;Proceed&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;To determine if the user has selected at least one product, a &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named
value&lt;/a&gt;, &lt;em&gt;HasSelection&lt;/em&gt;, uses this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(ProductScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;, ProductScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(ProductScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;; ProductScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link property&quot; parent-type=&quot;Button&quot; name=&quot;Enabled&quot;&gt;Enabled&lt;/span&gt; property of the &lt;strong&gt;Proceed&lt;/strong&gt; button and the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt; property of the form screen both
reference &lt;em&gt;HasSelection&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To understand how the formula above works, refer to &lt;a href=&quot;/blog/2024/08/06/switch-fields.html&quot;&gt;our last
tip&lt;/a&gt;, which covers this topic in detail.&lt;/p&gt;

&lt;p&gt;(If you’re on a &lt;a href=&quot;/pricing/&quot;&gt;Starter plan&lt;/a&gt; or an old plan, you may not have access
to named values. Here, you can simply use an invisible switch field instead of a
named value.)&lt;/p&gt;

&lt;p&gt;When users proceed to the next screen, they are presented with calculations
related to the first product they selected. When proceeding from that screen,
they are presented with calculations related to the second product they
selected, and so on.&lt;/p&gt;

&lt;p&gt;To make this work, formulas are associated with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;NextScreen&lt;/span&gt; property of all relevant screens, which
determines which screen is shown when the user moves forward.&lt;/p&gt;

&lt;p&gt;Here is the NextScreen formula of the first screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;ProductA!ThisOrFollowingScreen&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;ProductA!ThisOrFollowingScreen&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The idea here is that the screen that follows the first screen is either the
screen for the first product, &lt;em&gt;Product A&lt;/em&gt;, or a screen that follows it,
depending on what products have been toggled on the first screen.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThisOrFollowingScreen&lt;/code&gt; is a named value, belonging to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProductA&lt;/code&gt; screen,
with this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductA, ProductA, ProductScreen!ProductB, ProductB, ProductScreen!ProductC, ProductC, ProductScreen!ProductD, ProductD, ProductScreen!ProductE, ProductE, ProductScreen!ProductF, ProductF, ProductScreen!ProductG, ProductG, ProductScreen!ProductH, ProductH, ProductScreen!ProductI, ProductI, ProductScreen!ProductJ, ProductJ, LastScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductA; ProductA; ProductScreen!ProductB; ProductB; ProductScreen!ProductC; ProductC; ProductScreen!ProductD; ProductD; ProductScreen!ProductE; ProductE; ProductScreen!ProductF; ProductF; ProductScreen!ProductG; ProductG; ProductScreen!ProductH; ProductH; ProductScreen!ProductI; ProductI; ProductScreen!ProductJ; ProductJ; LastScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It’s a big formula, but it’s quite easy and repetitive. If &lt;em&gt;Product A&lt;/em&gt; has been
toggled to its “on” position on the first screen, the named value returns the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProductA&lt;/code&gt; screen. Otherwise, if &lt;em&gt;Product B&lt;/em&gt; has been toggled to its “on”
position, the named value returns the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProductB&lt;/code&gt; screen, and so on.&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;NextScreen&lt;/span&gt; property of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProductB&lt;/code&gt; screen uses
this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;ProductB!ThisOrFollowingScreen&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;ProductB!ThisOrFollowingScreen&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThisOrFollowingScreen&lt;/code&gt; named value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProductB&lt;/code&gt; uses this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductB, ProductB, ProductScreen!ProductC, ProductC, ProductScreen!ProductD, ProductD, ProductScreen!ProductE, ProductE, ProductScreen!ProductF, ProductF, ProductScreen!ProductG, ProductG, ProductScreen!ProductH, ProductH, ProductScreen!ProductI, ProductI, ProductScreen!ProductJ, ProductJ, LastScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductB; ProductB; ProductScreen!ProductC; ProductC; ProductScreen!ProductD; ProductD; ProductScreen!ProductE; ProductE; ProductScreen!ProductF; ProductF; ProductScreen!ProductG; ProductG; ProductScreen!ProductH; ProductH; ProductScreen!ProductI; ProductI; ProductScreen!ProductJ; ProductJ; LastScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It is identical to the formula of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThisOrFollowingScreen&lt;/code&gt; named value of the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProductA&lt;/code&gt; screen, but does not include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProductA&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(Again, these examples use named values, which are not available in Starter
plans. You can get these examples running by replacing the references to named
values in formulas with the formulas of the named values. It’s not as
convenient, but it works.)&lt;/p&gt;

&lt;p&gt;And that’s all there’s to it. Only the screens that are relevant to the user are
presented, and there is no need to go back to a list screen to select different
products.&lt;/p&gt;

&lt;p&gt;As a bonus, the last screen holds a tally of the costs of all the selected
products. Every screen has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cost&lt;/code&gt; field. To calculate the sum, this formula is
used:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductA, ProductA!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductB, ProductB!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductC, ProductC!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductD, ProductD!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductE, ProductE!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductF, ProductF!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductG, ProductG!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductH, ProductH!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductI, ProductI!Cost, 0), &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductJ, ProductJ!Cost, 0))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductA; ProductA!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductB; ProductB!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductC; ProductC!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductD; ProductD!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductE; ProductE!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductF; ProductF!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductG; ProductG!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductH; ProductH!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductI; ProductI!Cost; 0); &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ProductScreen!ProductJ; ProductJ!Cost; 0))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt; formula function is provided ten parameters, one for
every product. Each parameter is such that it returns the cost of a product if
the corresponding switch field has been switched to its “on” position on the
first screen, and zero otherwise.&lt;/p&gt;

&lt;p&gt;In effect, the sum total of all products that have been switched on is returned.&lt;/p&gt;

</description>
        <pubDate>Tue, 15 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2024/10/15/selectable-products.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2024/10/15/selectable-products.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Determine the number of toggled switch fields</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  This tip explores requiring users to flick a certain number of switch fields
  before being allowed to proceed.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Determine%20the%20number%20of%20toggled%20switch%20fields
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Sometimes, you need users to select a fixed number of options in the form of
switch fields. If the user toggles the wrong number of options, an error message
should be displayed and the user prevented from moving on the next screen:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 320px; width: 100%; max-width: 540px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=3dw81g&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;In the app above, exactly three fields must be toggled on — no more, no less.&lt;/p&gt;

&lt;p&gt;To accomplish this, we need the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;
functions. This formula is associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;
property of the text box displaying the error message:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;, MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)) &lt;span class=&quot;binaryOperator&quot; name=&quot;INEQUALITY&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;; MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)) &lt;span class=&quot;binaryOperator&quot; name=&quot;INEQUALITY&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; 3&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Let’s unpack the formula one part at a time.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;, MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;; MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)&lt;/span&gt;
filters the switch fields of &lt;em&gt;MainScreen&lt;/em&gt;, returning an array holding only those
switch fields that have been toggled to their on positions.&lt;/p&gt;

&lt;p&gt;The first parameter is the array to filter,
&lt;span class=&quot;formula decimalpoint&quot;&gt;MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;&lt;/span&gt;, which unsurprisingly consists of all
switch fields of &lt;em&gt;MainScreen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The second parameter is a logical array of the same size as the first array,
determining which elements to keep. &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1, 2 }, { FALSE, TRUE })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1; 2 }; { FALSE; TRUE })&lt;/span&gt;, for instance, returns &lt;span class=&quot;formula decimalpoint&quot;&gt;{ 2 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 2 }&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;When &lt;span class=&quot;formula decimalpoint&quot;&gt;MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;&lt;/span&gt; is provided as the second
parameter, Calcapp accesses the &lt;span class=&quot;link property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; property of
every switch field, meaning that &lt;span class=&quot;formula decimalpoint&quot;&gt;MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;&lt;/span&gt; and
&lt;span class=&quot;formula decimalpoint&quot;&gt;MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; are equivalent in this context.&lt;/p&gt;

&lt;p&gt;The end result is that an array consisting of only the switch fields whose
values are TRUE are returned from FILTER.&lt;/p&gt;

&lt;p&gt;Next, &lt;span class=&quot;link function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt; returns the number of elements of the array returned
from FILTER. In other words, SIZE returns the number of switch fields that have
been toggled on.&lt;/p&gt;

&lt;p&gt;Finally, remember that the overall formula is associated with the
&lt;span class=&quot;link property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property of the text box displaying the error
message. As the error message should be shown if not exactly three switch fields
have been toggled on, &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;lt;&amp;gt;&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; is used:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;, MainScreen.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)) &lt;span class=&quot;binaryOperator&quot; name=&quot;INEQUALITY&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;; MainScreen,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)) &lt;span class=&quot;binaryOperator&quot; name=&quot;INEQUALITY&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; 3&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To prevent users from moving on to the next screen if not exactly three switch
fields have been toggled on, the &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt;
property of the form screen should be used.&lt;/p&gt;
</description>
        <pubDate>Tue, 06 Aug 2024 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2024/08/06/switch-fields.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2024/08/06/switch-fields.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Bug report: Formulas now work better</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Named values can reference anything in an app and are a great way to cut down
  on formula repetition. They now work properly even when pushed to the maximum.
  We have fixed other issues as well.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;On occasion, we build apps for clients using Calcapp. This is often a great
way for a client to get started, by having us convert a spreadsheet and
demonstrating best practices in the process.&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;Contact us&lt;/a&gt; if you’d like to learn more about our professional
services.)&lt;/p&gt;

&lt;p&gt;It’s also great for us, as we get to spend some quality time using Calcapp, and
not just building and maintaining it. During the course of that work, we
sometimes find problems with Calcapp itself that we then track down and fix.&lt;/p&gt;

&lt;p&gt;This post details what we found and fixed this time around.&lt;/p&gt;

&lt;h2 id=&quot;the-item-formula-parameter&quot;&gt;The Item formula parameter&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;In August last year&lt;/a&gt;, we introduced support for
accessing the current item from a formula &lt;a href=&quot;/blog/2023/08/11/edit-multiple-formulas.html&quot;&gt;simply by writing
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s say that you have this &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; formula
connected to &lt;em&gt;NumberField1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;NumberField1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; MaximumReading&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;NumberField1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; MaximumReading&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s assume that you have a hundred such number fields, which all
should use similar formulas connected to their Valid properties
(&lt;span class=&quot;formula decimalpoint&quot;&gt;NumberField2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; MaximumReading&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;NumberField2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; MaximumReading&lt;/span&gt;, etc).&lt;/p&gt;

&lt;p&gt;That quickly becomes hard to maintain and repetitive, as changing the formula
now involves changing one hundred of them. Wouldn’t it be great if they all
could use the same formula? Had that been the case, you could actually &lt;a href=&quot;/blog/2023/08/11/edit-multiple-formulas.html&quot;&gt;edit
them all at the same time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; facilitates. It’s a stand-in for the item itself, in this
case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NumberField1&lt;/code&gt; and others. So you can use this formula instead:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Item &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; MaximumReading&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Item &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; MaximumReading&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;While the formula above worked fine prior to this fix, there are other valid
formulas that produced error messages until we released the fix today.&lt;/p&gt;

&lt;p&gt;Specifically, consider a number field. There are properties that are specific to
number fields (like &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;MaximumValue&quot;&gt;MaximumValue&lt;/span&gt;) and there are
properties that are supported by all kinds of fields, including text fields and
date and time fields (like (&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;).&lt;/p&gt;

&lt;p&gt;Associating a formula with a property specific to a number field would enable
said formula to access an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; value offering the full set of properties
supported by number fields. However, a formula associated with a property shared
between all kinds of fields would have access to an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; value only offering
access to the shared properties, not the ones specific to number fields.&lt;/p&gt;

&lt;p&gt;In other words, formulas associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;
property of a number field could not access properties specific to number
fields, like &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;MaximumValue&quot;&gt;MaximumValue&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;That was an oversight on our part, and has now been fixed.&lt;/p&gt;

&lt;h2 id=&quot;named-values&quot;&gt;Named values&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;Named values&lt;/a&gt; have also been available since August last year.
They can be used to represent any value a formula can represent. The new &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data
editor&lt;/a&gt; uses them to great effect to represent tabular data.&lt;/p&gt;

&lt;p&gt;However, named values can truly represent anything, and when we worked on our
last client project we wanted to make full use of them. The only problem was
that they did not appear to work right.&lt;/p&gt;

&lt;p&gt;Here’s an app that demonstrates the problem, being edited in Calcapp Creator:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2024-06-13-formula-bugs/creator-zero.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2024-06-13-formula-bugs/creator-zero.png&quot; alt=&quot;An app failing to calculate property in Calcapp Creator&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Users enter miles traveled in the number fields of the app. Only number fields
related to the selected state are shown, which is accomplished using a text
drop-down field and the &lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property of the form
groups housing the number fields.&lt;/p&gt;

&lt;p&gt;To cut down on repetition, we use a number of named values to represent various
parts of the app. First, there’s the &lt;em&gt;Legs&lt;/em&gt; named value, which allows us to
reference the relevant number fields from elsewhere in the app.&lt;/p&gt;

&lt;p&gt;Here’s its formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wisconsin.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;, Wisconsin.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;, Missouri.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;, Missouri.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wisconsin,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;; Wisconsin,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;; Missouri,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;; Missouri,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In other words, if the &lt;em&gt;Wisconsin&lt;/em&gt; form group is visible, because the user has
selected &lt;strong&gt;Wisconsin&lt;/strong&gt; from the text drop-down field, &lt;em&gt;Legs&lt;/em&gt; references the
number fields of the &lt;em&gt;Wisconsin&lt;/em&gt; form group. Conversely, &lt;em&gt;Legs&lt;/em&gt; references the
number fields of the Missouri form group if &lt;strong&gt;Missouri&lt;/strong&gt; has been selected from
the text drop-down field.&lt;/p&gt;

&lt;p&gt;Next, let’s say that the only miles traveled that are deemed eligible are those
that are 100 miles or less. To accomplish that, each number field uses a
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;MaximumValue&quot;&gt;MaximumValue&lt;/span&gt; property which is set to 100.&lt;/p&gt;

&lt;p&gt;The final named value is named &lt;em&gt;EligibleMiles&lt;/em&gt; and includes only those number
fields whose values are 100 or less. Here’s its formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Legs, Legs.Value.Valid)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Legs; Legs,Value,Valid)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It filters the number fields identified by the &lt;em&gt;Legs&lt;/em&gt; named value by only
including those that are valid, that is, have values that are 100 or less.&lt;/p&gt;

&lt;p&gt;(You might be tempted to write &lt;span class=&quot;formula decimalpoint&quot;&gt;Legs.Valid&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Legs,Valid&lt;/span&gt;, but that
would reference a Valid property belonging directly to the &lt;em&gt;Legs&lt;/em&gt; named value.
There is no such property — &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; is a property of
fields. As such, the &lt;span class=&quot;link property&quot; parent-type=&quot;NamedValue&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; property of the named
value must be accessed explicitly in the formula. As it references number
fields, &lt;span class=&quot;formula decimalpoint&quot;&gt;.Valid&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;,Valid&lt;/span&gt; can be written directly following
&lt;span class=&quot;formula decimalpoint&quot;&gt;.Value&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;,Value&lt;/span&gt; in the formula.)&lt;/p&gt;

&lt;p&gt;Finally, the last number field displays the sum total of all eligible miles that
have been entered, using this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(EligibleLegs)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(EligibleLegs)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The only problem with this app? Before our update this morning, it just plain
didn’t work. As you can see in the screenshot above, the sum of all eligible
legs was always zero.&lt;/p&gt;

&lt;p&gt;There were other problems as well:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2024-06-13-formula-bugs/creator-error.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2024-06-13-formula-bugs/creator-error.png&quot; alt=&quot;An app displaying invalid errors edited in Calcapp Creator&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app above contains only valid formulas, and yet, many of them are flagged as
invalid.&lt;/p&gt;

&lt;p&gt;The root cause was that Calcapp did not handle multiple levels of indirection
well with named values. We have spent weeks completely overhauling this part of
Calcapp and are happy to report that everything now works properly.&lt;/p&gt;

&lt;p&gt;While the example above is admittedly somewhat contrived, we keep encountering
situations where named values make for shorter, easier-to-read formulas. Even if
you push them to the maximum, they should now work properly.&lt;/p&gt;

&lt;h2 id=&quot;other-fixes&quot;&gt;Other fixes&lt;/h2&gt;

&lt;p&gt;We also encountered a few other issues. The parameter popup, that displays
information on the function parameter you’re editing, would sometimes fail to
close when you moved away from the formula field.&lt;/p&gt;

&lt;p&gt;Also, you have been able to determine the &lt;a href=&quot;/blog/2023/08/11/inspector-screen.html&quot;&gt;next screen&lt;/a&gt; of
list screen navigators since our &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;August release&lt;/a&gt;.
Unfortunately, though, when moving between navigators, the next screen in the
inspector would sometimes fail to update.&lt;/p&gt;

&lt;p&gt;As of today, both issues have been fixed.&lt;/p&gt;

</description>
        <pubDate>Thu, 13 Jun 2024 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2024/06/13/formula-bugs.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2024/06/13/formula-bugs.html</guid>
        
        <category>Bug report</category>
        
        
      </item>
    
      <item>
        <title>Bug report: A grab bag of fixes</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We recently fixed three issues, ranging from server reliability issues to
  minor problems with the user experience. This blog post explores all three.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Even when we appear to be quiet, a lot of work is going on behind the scenes to
ensure that Calcapp continues performing to your expectations. In this post,
we’ll highlight some of that work.&lt;/p&gt;

&lt;h2 id=&quot;server-reliability&quot;&gt;Server reliability&lt;/h2&gt;

&lt;p&gt;Calcapp experiences very little downtime, meaning that apps can be edited and
run at all hours. We don’t have any “maintenance windows” during which Calcapp
is unavailable. Even when we &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;release major updates&lt;/a&gt;, we
ensure that apps can be run, even if we have to disable app editing for a short
while.&lt;/p&gt;

&lt;p&gt;Unfortunately, we have experienced some server downtime lately. We noticed this
issue several weeks ago, and started monitoring the situation closely.&lt;/p&gt;

&lt;p&gt;Today, we once again experienced downtime, and noticed that the culprit was an
innocuous-looking invalid formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field4 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field5 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field6 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field7 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field8 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field9 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field10 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field11 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field12 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field13 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field15&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field4 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field5 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field6 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field7 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field8 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field9 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field10 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field11 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field12 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field13 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Field15&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Notice the problem? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1&lt;/code&gt; has been subtly misspelled, “F” should not appear
in lower case.&lt;/p&gt;

&lt;p&gt;For various reasons, that particular invalid formula threw us for a loop, taking
literally hours for our server to make sense of. (Had there been fewer field
references in the formula, or had the misspelled field appeared later in the
formula, there would have been no issue.)&lt;/p&gt;

&lt;p&gt;Once we realized what the problem was, we were able to quickly fix it.&lt;/p&gt;

&lt;p&gt;Bonus tip: If you want to sum all fields from Field1 through Field15,
&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field15)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field15)&lt;/span&gt; is preferable to the formula above. It’s
shorter, easier to maintain and wouldn’t have caused the performance issue that
brought our server to its knees.&lt;/p&gt;

&lt;h2 id=&quot;editing-data-tables-with-line-breaks&quot;&gt;Editing data tables with line breaks&lt;/h2&gt;

&lt;p&gt;A customer noticed a disconcerting problem today. Using our new-ish &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data
editor&lt;/a&gt;, adding text cells with line breaks worked fine. (You can
press &lt;kbd&gt;Alt&lt;/kbd&gt;+&lt;kbd&gt;Enter&lt;/kbd&gt; to insert them.) However, editing the data
would produce a blank data editor, as though there was nothing there for it to
edit.&lt;/p&gt;

&lt;p&gt;While the data wasn’t technically lost, it appeared that way to our customer, as
it became hard to edit. (Editing the formulas produced by the data editor would
have worked as expected, though.)&lt;/p&gt;

&lt;p&gt;Luckily, we were able to quickly find the culprit. We delivered the fix to our
customer within an hour of receiving the report.&lt;/p&gt;

&lt;h2 id=&quot;copying-and-pasting-fields&quot;&gt;Copying and pasting fields&lt;/h2&gt;

&lt;p&gt;We’d like to think that Calcapp Creator looks simple on the surface, but hides
lots of time-saving features. One such feature is that formulas are
automatically updated when you change the names of various items, like fields
and buttons, that may be referenced from formulas.&lt;/p&gt;

&lt;p&gt;Another such feature is that formulas are automatically updated when you copy
and paste fields. Consider two input fields, &lt;em&gt;A&lt;/em&gt; and &lt;em&gt;B&lt;/em&gt;, and a result field
&lt;em&gt;Result&lt;/em&gt;, whose formula is &lt;span class=&quot;formula decimalpoint&quot;&gt;A &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; B&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;A &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; B&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;If you copy these three fields and paste them back on the same screen, the new
&lt;em&gt;A&lt;/em&gt; field is named &lt;em&gt;A2&lt;/em&gt; and the new &lt;em&gt;B&lt;/em&gt; field is named &lt;em&gt;B2&lt;/em&gt; (so as to not
conflict with the existing &lt;em&gt;A&lt;/em&gt; and &lt;em&gt;B&lt;/em&gt; fields). The formula of the new &lt;em&gt;Result&lt;/em&gt;
field (&lt;em&gt;Result2&lt;/em&gt;) is changed to read &lt;span class=&quot;formula decimalpoint&quot;&gt;A2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; B2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;A2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; B2&lt;/span&gt;, as Calcapp
Creator assumes that it should reference the new fields and not the old ones.&lt;/p&gt;

&lt;p&gt;Unfortunately, this feature broke &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;in August last year&lt;/a&gt;. An
intrepid customer noticed, and we were able to quickly fix the issue.&lt;/p&gt;

&lt;p&gt;The moral of the story? If you notice unexpected behavior, please get in touch.
We are deeply committed to giving you a quality experience with Calcapp, but if
anything is amiss, we can’t do anything about it if we are not made aware.&lt;/p&gt;

&lt;p&gt;In other words, please contact us through the chat widget or by &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;emailing
us&lt;/a&gt; if Calcapp is not performing to your satisfaction.&lt;/p&gt;

</description>
        <pubDate>Thu, 09 May 2024 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2024/05/09/bugs.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2024/05/09/bugs.html</guid>
        
        <category>Bug report</category>
        
        
      </item>
    
      <item>
        <title>Tip: Calculate the elapsed time between two dates without DATEDIF</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Calculating the number of days, months or years between two dates can be done
  with DATEDIF in Excel, or using plain formulas in Calcapp. These formulas are
  explored in this tip.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Calculating the number of days, months or years between two dates is a common
scenario in apps created with Calcapp. Excel provides the &lt;a href=&quot;https://support.microsoft.com/en-us/office/datedif-function-25dba1a4-2812-480b-84dd-8b32a451b35c&quot;&gt;DATEDIF&lt;/a&gt;
formula function for this purpose, but Calcapp does not currently support it.&lt;/p&gt;

&lt;p&gt;(DATEDIF is a compatibility function Microsoft added to support Lotus 1-2-3, a
competing spreadsheet which was principally popular in the 1980s. While it isn’t
fully supported by Excel – it doesn’t appear in the &lt;a href=&quot;https://support.microsoft.com/en-us/office/insert-function-74474114-7c7f-43f5-bec3-096c56e2fb13&quot;&gt;Insert Function dialog
box&lt;/a&gt; – it is still commonly used.)&lt;/p&gt;

&lt;p&gt;In this post, we’ll look at a few popular ways that DATEDIF is used and
determine how to achieve the exact same results with Calcapp, without DATEDIF.&lt;/p&gt;

&lt;p&gt;All the formula examples assume that there are two date and time fields named
&lt;em&gt;Date1&lt;/em&gt; and &lt;em&gt;Date2&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;calculating-the-number-of-days-between-two-dates&quot;&gt;Calculating the number of days between two dates&lt;/h2&gt;

&lt;p&gt;When DATEDIF is used with its third parameter set to “D”, the number of complete
days between two dates is calculated.&lt;/p&gt;

&lt;p&gt;Both Excel and Calcapp represent dates as so-called &lt;em&gt;sequential serial numbers&lt;/em&gt;.
The integer part of the number represents the number of days that have elapsed
since December 31, 1899, and the fractional part represents the time of day.
(&lt;span class=&quot;link property&quot; parent-type=&quot;DateTimeField&quot; name=&quot;Value&quot;&gt;Learn more here&lt;/span&gt;.)&lt;/p&gt;

&lt;p&gt;As such, the number 10.75 represents the 10th of January, 1900, at 6 PM (18:00).
(0.75 means that three quarters of a day have elapsed.)&lt;/p&gt;

&lt;p&gt;Armed with this knowledge, determining the number of days between two dates is
easy: we just subtract one number from the other:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If the two dates have time components, the formula above returns a fractional
number, unlike DATEDIF. To more fully replicate the behavior of DATEDIF, which
only counts whole days, we’ll need to remove the fractional component using the
&lt;span class=&quot;link function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If &lt;em&gt;Date1&lt;/em&gt; represents a later date than &lt;em&gt;Date2&lt;/em&gt;, we’ll get a negative number.
There are two approaches to solving this issue that we’ll explore here. DATEDIF
returns a #NUM! error, but our favored approach is to make the negative number a
positive one using &lt;span class=&quot;link function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To instead return a #N/A error (there is no way to manually return a #NUM!
error), we can use the &lt;span class=&quot;link function&quot; name=&quot;NA&quot;&gt;NA&lt;/span&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; Date1, &lt;span class=&quot;function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1), &lt;span class=&quot;function&quot; name=&quot;NA&quot;&gt;NA&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; Date1; &lt;span class=&quot;function&quot; name=&quot;TRUNC&quot;&gt;TRUNC&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; Date1); &lt;span class=&quot;function&quot; name=&quot;NA&quot;&gt;NA&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;calculating-the-number-of-months-between-two-dates&quot;&gt;Calculating the number of months between two dates&lt;/h2&gt;

&lt;p&gt;When DATEDIF is used with its third parameter set to “M”, the number of complete
months between two dates is calculated.&lt;/p&gt;

&lt;p&gt;To make work easier for us, we’ll fully follow the DATEDIF approach here, of
requiring that &lt;em&gt;Date2&lt;/em&gt; represents a later date than &lt;em&gt;Date1&lt;/em&gt;, and otherwise
return a #N/A error.&lt;/p&gt;

&lt;p&gt;To account for dates that fall on different years, we use the
&lt;span class=&quot;link function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt; function to extract the different years, and multiply that
number by 12 to get the number of months. We add that number to the number of
months that differ between the two dates, a number we get from invoking the
&lt;span class=&quot;link function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt; function on both dates and subtracting the &lt;em&gt;Date1&lt;/em&gt; number
from the &lt;em&gt;Date2&lt;/em&gt; number.&lt;/p&gt;

&lt;p&gt;Lastly, we need to ensure that only complete months are counted. If the dates
fall on different days, we therefore subtract one from the calculated value.&lt;/p&gt;

&lt;p&gt;Here’s the finished formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; Date1, (&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date1)) &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 12 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt;(Date1)) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date1), 1, 0), &lt;span class=&quot;function&quot; name=&quot;NA&quot;&gt;NA&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Date2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; Date1; (&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date1)) &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 12 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt;(Date1)) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date1); 1; 0); &lt;span class=&quot;function&quot; name=&quot;NA&quot;&gt;NA&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;calculating-the-number-of-years-between-two-dates&quot;&gt;Calculating the number of years between two dates&lt;/h2&gt;

&lt;p&gt;When DATEDIF is used with its third parameter set to “Y”, the number of complete
years between two dates is calculated.&lt;/p&gt;

&lt;p&gt;The formula for performing the calculation is similar to the one for calculating
the number of complete months:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date1) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;INEQUALITY&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date1), 1, 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date1) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date2) &lt;span class=&quot;binaryOperator&quot; name=&quot;INEQUALITY&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date1); 1; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;DATEDIF also supports the “MD”, “YM” and “YD” units, which ignores various date
components. &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;Let us know&lt;/a&gt; if you’d like us to cover those variations
as well!&lt;/p&gt;

</description>
        <pubDate>Fri, 23 Feb 2024 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2024/02/23/datedif.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2024/02/23/datedif.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Sample app: Store invisible, permanent information when a button is pressed</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Apps can store invisible information when a button is pressed, which is
  retained even when the app is closed. Our sample app uses this technique to
  enforce that a button is only pressed once per day.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Sample%3A%20Daily%20yield%20report
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on this sample app ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;We see a lot of apps built with Calcapp that simply collect information and send
it back to the office. But what if the user should only be allowed to send the
data once per day?&lt;/p&gt;

&lt;p&gt;Prior to &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;our last release&lt;/a&gt;, it wasn’t possible for an app
to enforce such a rule. Now, though, you can use formula buttons, in conjunction
with persistent fields, to make this a reality.&lt;/p&gt;

&lt;p&gt;The technique described in this post is applicable to many other kinds of apps.
We will demonstrate a technique enabling buttons to store information — any
information — for subsequent use when the user comes back to the app, even
after restarting their device.&lt;/p&gt;

&lt;p&gt;You’re encouraged to view the app and its formulas as you read along. It’s
available as a template when you create a new app under the &lt;em&gt;Sample: Daily yield
report&lt;/em&gt; name.&lt;/p&gt;

&lt;h1 id=&quot;usage&quot;&gt;Usage&lt;/h1&gt;

&lt;p&gt;Without further ado, here’s the app:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 665px; width: 100%; max-width: 540px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=s8jfox&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;The user is expected to fill out the yield once per day. When the button is
pressed, the data is emailed back to the office and a message appears. If the
user has never submitted the yield before, a simple message informs the user
that the data has been submitted. Otherwise, the yield difference is also
displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-12-21-persistent-button-state/success.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-12-21-persistent-button-state/success.png&quot; alt=&quot;The message that is displayed when the information is submitted             successfully&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the user tries to submit the yield again the same day, this message appears:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-12-21-persistent-button-state/warning.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-12-21-persistent-button-state/warning.png&quot; alt=&quot;The message that is displayed when an attempt is made to submit the            data twice the same day&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;

&lt;p&gt;The key to the app is the use of a formula button, which runs formulas in
response to being pressed. Refer to &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;our blog post from August&lt;/a&gt;
to learn more.&lt;/p&gt;

&lt;p&gt;Action formulas have access to &lt;a href=&quot;/learn/formulas/section-action.html&quot;&gt;special functions&lt;/a&gt;. Here,
we’ll use the &lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt; function to email data back to the
office.&lt;/p&gt;

&lt;p&gt;Action formulas also have access to &lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt;, which assigns values to
properties. For instance, &lt;code&gt;:=&lt;/code&gt; can be used to change the
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;values&lt;/span&gt; of fields.&lt;/p&gt;

&lt;p&gt;The key to making this app work is that it has two
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;hidden fields&lt;/span&gt;, which are also
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Persistent&quot;&gt;persistent&lt;/span&gt;. A persistent field stores its value
to the user’s device, which is read back when the app is started again.&lt;/p&gt;

&lt;p&gt;(Unfortunately, that means that the user is allowed to submit the yield on their
cell phone and on their desktop computer, all on the same day.)&lt;/p&gt;

&lt;p&gt;The field where the user enters the yield is named &lt;em&gt;Yield&lt;/em&gt;. There’s also a
hidden, persistent field named &lt;em&gt;LastYield&lt;/em&gt;. A final hidden, persistent field is
&lt;em&gt;LastSubmissionDate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The formula button is grayed-out if the user hasn’t filled in the &lt;em&gt;Yield&lt;/em&gt; field.
To achieve that, this formula is associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Enabled&quot;&gt;Enabled&lt;/span&gt; property of the button:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(Yield)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(Yield)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Next, here’s part of the action formula associated with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt; property of the formula button:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; LastSubmissionDate), &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;A yield has already been reported today, please&lt;br /&gt;return tomorrow.&quot;, &quot;Warning&quot;), …)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; LastSubmissionDate); &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;A yield has already been reported today, please&lt;br /&gt;return tomorrow.&quot;; &quot;Warning&quot;); …)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Above, we’re only looking at a part of the formula. The elided part has been
replaced with &lt;code&gt;…&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The formula above checks the &lt;em&gt;LastSubmissionDate&lt;/em&gt; field and its value. If it is
defined (meaning that it holds a value) and it is equal to the return value of
&lt;span class=&quot;link function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;, or greater than it, a warning message is displayed using
the &lt;span class=&quot;link function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt; function, warning the user that they have already
pressed the button today.&lt;/p&gt;

&lt;p&gt;The first time the app is started, &lt;em&gt;LastSubmissionDate&lt;/em&gt; does not hold a value,
meaning that &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate)&lt;/span&gt; returns FALSE and
the message isn’t shown. (&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&amp;amp;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; means “and”.)&lt;/p&gt;

&lt;p&gt;Today’s date should be stored in the &lt;em&gt;LastSubmissionDate&lt;/em&gt; field when the button
is pressed. To do so, this formula fragment must be run by the button:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;LastSubmissionDate &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;()&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;LastSubmissionDate &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;()&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The next time the button is pressed,
&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate)&lt;/span&gt; returns TRUE and the next part
of the formula, &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; LastSubmissionDate&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; LastSubmissionDate&lt;/span&gt; is evaluated.
That part only returns TRUE if the value stored in &lt;em&gt;LastSubmissionDate&lt;/em&gt;
indicates that the button was last pressed on the same day (or in the future),
which makes the button display the warning message.&lt;/p&gt;

&lt;p&gt;We also need to store the yield when the button is pressed, so that we can show
the change in the submission message:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;LastYield &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Yield&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;LastYield &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Yield&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Here’s the full formula fragment that was elided with &lt;code&gt;…&lt;/code&gt; in the action
formula above, which is run if the warning message isn’t displayed:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ Yield }, &quot;office@example.com&quot;); &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Submission successful.&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastYield), &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Yield&lt;br /&gt;difference: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;((Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; LastYield) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100, 0, 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;%&quot;), &quot;Success&quot;); LastYield &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Yield; LastSubmissionDate &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;()&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ Yield }; &quot;office@example.com&quot;);; &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Submission successful.&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastYield); &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Yield&lt;br /&gt;difference: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;((Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; LastYield) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100; 0; 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;%&quot;); &quot;Success&quot;);; LastYield &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Yield;; LastSubmissionDate &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;()&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ Yield }, &quot;office@example.com&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ Yield }; &quot;office@example.com&quot;)&lt;/span&gt; sends
email to the office, containing just the yield. (A real app should probably also
collect the user’s identity and send that as part of the report.)&lt;/p&gt;

&lt;p&gt;The ALERT part of the formula shows a message to the user, informing them that
the submission was successful. It also displays the yield difference using this
formula fragment:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;((Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; LastYield) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100, 0, 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;%&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;((Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; LastYield) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100; 0; 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;%&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;FORMATNUMBER above takes a number and formats it. In this case, it uses a
minimum of zero decimal places, and a maximum of two decimal places.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; joins text strings together. Above, it adds a percentage sign
to the end of the number displayed to the user.&lt;/p&gt;

&lt;p&gt;Finally, the formula fragment assigns values to the hidden, persistent fields
&lt;em&gt;LastYield&lt;/em&gt; and &lt;em&gt;LastSubmissionDate&lt;/em&gt;, which is the information that makes the
app work.&lt;/p&gt;

&lt;p&gt;Taking it all together, here’s the full action formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; LastSubmissionDate), &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;A yield has already been reported today, please&lt;br /&gt;return tomorrow.&quot;, &quot;Warning&quot;), &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ Yield }, &quot;office@example.com&quot;); &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Submission successful.&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastYield), &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Yield&lt;br /&gt;difference: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;((Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; LastYield) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100, 0, 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;%&quot;), &quot;Success&quot;); LastYield &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Yield; LastSubmissionDate &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastSubmissionDate) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; LastSubmissionDate); &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;A yield has already been reported today, please&lt;br /&gt;return tomorrow.&quot;; &quot;Warning&quot;); &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ Yield }; &quot;office@example.com&quot;);; &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Submission successful.&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(LastYield); &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Yield&lt;br /&gt;difference: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;((Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; LastYield) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; Yield &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100; 0; 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;%&quot;); &quot;Success&quot;);; LastYield &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Yield;; LastSubmissionDate &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

</description>
        <pubDate>Thu, 21 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/12/21/persistent-button-state.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/12/21/persistent-button-state.html</guid>
        
        <category>Sample app</category>
        
        
      </item>
    
      <item>
        <title>Feature: Streamlined experience for our Unlimited plan</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our Unlimited plan offers an experience completely free of limits, now
  supported by a new streamlined user interface.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Some of our customers have requirements not easily met by our regular plans.
Those needs may include thousands of public apps, or tens of thousands of users
of private apps, which would be cost-prohibitive with our regular plans.&lt;/p&gt;

&lt;p&gt;Still other customers may prefer not to pay extra for every public app
they create, and instead pay a fixed yearly fee for unlimited access to Calcapp.&lt;/p&gt;

&lt;p&gt;We have accommodated these customers from the start with our Unlimited plan, but
the experience has not been tailored for them. That changes today.&lt;/p&gt;

&lt;p&gt;Here’s the start screen for an app, with an Unlimited plan:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-09-24-unlimited/start.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-09-24-unlimited/start.png&quot; alt=&quot;The start screen for our Unlimited plan&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice anything different? The &lt;strong&gt;Change plan&lt;/strong&gt; button is no longer in the
upper-left corner. Instead, there is a simple toggle between private and public
apps. Much easier.&lt;/p&gt;

&lt;p&gt;Also, the &lt;strong&gt;Manage apps&lt;/strong&gt; window now only differentiates between public and
private apps (instead of listing all your apps by plan):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-09-24-unlimited/apps.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-09-24-unlimited/apps.png&quot; alt=&quot;The Manage apps window for our Unlimited plan&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pricing of our Unlimited plan is determined through negotiation.
&lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;Contact us&lt;/a&gt; to learn more.&lt;/p&gt;
</description>
        <pubDate>Sun, 24 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/09/24/unlimited.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/09/24/unlimited.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Release: Our August, 2023 update is here</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our most significant release yet is here, with 23 blog posts to describe it
  all. Build previously-unthinkable apps with action formulas. Import and edit
  spreadsheet-like data and use eleven new button types. The app designer now
  supports undo, formula autocomplete, a new email editor and much more.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;


&lt;a href=&quot;/assets/media/blog/2023-08-11-release/wallpaper-5k.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-release/wallpaper-1080p.png&quot;
       alt=&quot;An image commemorating the release&quot;
       class=&quot;large-image no-shadow&quot;&gt;&lt;/a&gt;

&lt;h2&gt;What&apos;s new?&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Eleven new button types.&lt;/strong&gt;
    Eleven new types of buttons make your apps easier to use and more powerful.
    Buttons can run action formulas, change the active screen, copy text to the
    clipboard, show messages and more.
    &lt;a href=&quot;/blog/2023/08/11/new-buttons.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Make buttons perform actions with action formulas.&lt;/strong&gt;
    Action formulas make things happen, unlike regular functions, which just
    calculate values. They are our biggest new feature ever. Use them to model
    complex business logic when buttons are pressed.
    &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;An editor for tabular data.&lt;/strong&gt;
    Our new data editor allows you to easily create and edit spreadsheet-like
    data tables. Data can be imported from spreadsheets through copy and paste.
    Use XLOOKUP to look up values in data tables.
    &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Undo and redo.&lt;/strong&gt;
    Calcapp Creator now features undo and redo buttons that bring your work back
    if you inadvertently delete it.
    &lt;a href=&quot;/blog/2023/08/11/undo.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Autocomplete for formulas.&lt;/strong&gt;
    Our new formula autocomplete system provides helpful suggestions for what
    you may want to type next. To reference a field on any screen, just type
    part of its name or label and let us do the rest.
    &lt;a href=&quot;/blog/2023/08/11/autocomplete.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Edit text properties as templates.&lt;/strong&gt;
    All text properties can now be edited as templates. Change the text as you
    normally would in the inspector and insert formula fragments between special
    markers. This makes it much easier to edit email bodies sent by your app.
    &lt;a href=&quot;/blog/2023/08/11/templates.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Access all items as a single array.&lt;/strong&gt;
    The new Items property allows you to access all items, including fields and
    buttons, as a single array. That makes it easy to calculate the sum of all
    fields of a screen, or determine if all fields of your app are valid, with
    short, readable formulas.
    &lt;a href=&quot;/blog/2023/08/11/items.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Edit formulas of multiple items at the same time.&lt;/strong&gt;
    When multiple items are checked in the app designer, you can now edit all
    their formulas at the same time. We also describe the new special formula
    value Item and various performance improvements.
    &lt;a href=&quot;/blog/2023/08/11/edit-multiple-formulas.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;A grab bag of new features.&lt;/strong&gt;
    The screens sidebar can now be resized, line breaks can be inserted into
    formulas, sliders work better on touch screens and you get more disk space
    for images. Our latest release is full of minor features such as these.
    &lt;a href=&quot;/blog/2023/08/11/grab-bag.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Use LET to avoid repetition in formulas.&lt;/strong&gt;
    The new function LET enables you to assign names to values for use inside a
    single formula. LET can make formulas shorter and easier to read and can
    help them run faster.
    &lt;a href=&quot;/blog/2023/08/11/let-function.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Named values.&lt;/strong&gt;
    Named values allow you to assign names to values returned from formulas.
    Unlike hidden fields, named values can represent anything a formula can
    return, including screens and arrays.
    &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Customizable link targets.&lt;/strong&gt;
    Browse buttons and the BROWSE function allow you to determine if links open
    in a new web browser window or tab or replace the app. An app-wide default
    setting can also be changed, which also affects where text box links open.
    &lt;a href=&quot;/blog/2023/08/11/link-target.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Improvements to reports.&lt;/strong&gt;
    The bodies of sent emails can now be edited as a template, making for a more
    comfortable experience. The fields to include can be set visually. Most
    report-related properties can now be set through formulas, and
    report-related action functions offer lots of flexibility.
    &lt;a href=&quot;/blog/2023/08/11/better-reports.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;More ways to access our documentation.&lt;/strong&gt;
    Our documentation is now integrated into Calcapp Creator. A popup now
    appears with function parameter information when editing formulas.
    Documentation is also part of autocomplete.
    &lt;a href=&quot;/blog/2023/08/11/better-documentation.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;
      Easily determine what fields to reset or include in a report.
    &lt;/strong&gt;
    The fields to reset and the fields to include in a report can now be set
    directly in the inspector, without using a formula.
    &lt;a href=&quot;/blog/2023/08/11/inspector-fields.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Easily decide the next screen.&lt;/strong&gt;
    The screen following other screens and navigators can now be set directly in
    the inspector, without using a formula.
    &lt;a href=&quot;/blog/2023/08/11/inspector-screen.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Named function parameters.&lt;/strong&gt;
    Function parameters can now be named, making formulas easier to read. Named
    parameters can also make formulas significantly shorter.
    &lt;a href=&quot;/blog/2023/08/11/named-parameters.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Tips for getting the most out of Calcapp&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Ask users questions with action formulas.&lt;/strong&gt;
    Use action formulas to ask users a series of questions. The answers are then
    fed into action functions that act on the information given.
    &lt;a href=&quot;/blog/2023/08/11/asking-questions.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Perform calculations when a button is pressed.&lt;/strong&gt;
    Use a formula button to calculate results only when a button is pressed,
    instead of while the user is typing. This technique uses the new assignment
    operator.
    &lt;a href=&quot;/blog/2023/08/11/calculation-buttons.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Require a button to be pressed.&lt;/strong&gt;
    Prevent users from seeing certain information, or from moving on to the next
    screen, if a button has not been pressed. This can be achieved through a
    formula button and a hidden field.
    &lt;a href=&quot;/blog/2023/08/11/required-button.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;More news&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Changes to our subscription plans.&lt;/strong&gt;
    We are introducing a new set of plans at higher price points. Existing apps
    stay on the old plans at the old prices, with access to most of our new
    features. The new button types, the data editor, named values and action
    formulas require you to upgrade to a 2023 plan.
    &lt;a href=&quot;/blog/2023/08/11/plans.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Sample app: Edit tags using action formulas.&lt;/strong&gt;
    This sample app allows users to edit tags, which are often used on online
    marketplaces like eBay. The app demonstrates many new Calcapp features, like
    action formulas, the LET function, navigation buttons and clipboard copy
    buttons.
    &lt;a href=&quot;/blog/2023/08/11/tag-editor.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 11 Aug 2023 22:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/release.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/release.html</guid>
        
        <category>Release</category>
        
        
      </item>
    
      <item>
        <title>Feature: Eleven new button types</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Eleven new types of buttons make your apps easier to use and more powerful.
  Buttons can run action formulas, change the active screen, copy text to the
  clipboard, show messages and more.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;For the longest time, Calcapp has offered four different button types:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2016/10/17/reset-fields.html&quot;&gt;Reset buttons&lt;/a&gt; reset fields.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2016/10/18/reporting-email.html&quot;&gt;Email report buttons&lt;/a&gt; send reports through email.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.calcapp.net/blog/2017/10/29/reporting-download.html&quot;&gt;Open report buttons&lt;/a&gt; open reports on the user’s device.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2016/10/19/reporting-server.html&quot;&gt;Server relay buttons&lt;/a&gt;, which send data to other servers
(&lt;a href=&quot;/blog/2018/05/18/zapier-video.html&quot;&gt;often through Zapier&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;Today&lt;/a&gt; changes. We’re now introducing a whopping
eleven new button types, which will make your apps easier to use and more
powerful.&lt;/p&gt;

&lt;p&gt;Here’s the full list:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Formula buttons&lt;/strong&gt; run action formulas.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Alert buttons&lt;/strong&gt; show messages.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clipboard copy buttons&lt;/strong&gt; copy text to the clipboard.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Go back and go forward buttons&lt;/strong&gt; change the active screen.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Print screen buttons&lt;/strong&gt; launch the user’s print dialog.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Compose email buttons&lt;/strong&gt; launch the user’s email client.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Compose SMS buttons&lt;/strong&gt; launch the user’s text message client.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dial buttons&lt;/strong&gt; launch the user’s dialer.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Open map buttons&lt;/strong&gt; show maps using the user’s map app.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Browse buttons&lt;/strong&gt; show a web page in the user’s web browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The new button types are not available in any of our legacy plans, meaning that
you may need to upgrade to access them. Most new buttons types are available in
our &lt;a href=&quot;/blog/2023/08/11/plans.html&quot;&gt;2023 Business plans&lt;/a&gt;. All button types, including formula buttons,
are available in our 2023 White Label plans. Everything is fully functional in
Calcapp Creator’s preview sidebar, though, so you can get a feel for the new
features, regardless of your plan.&lt;/p&gt;

&lt;h2 id=&quot;formula-buttons&quot;&gt;Formula buttons&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Formula buttons&lt;/strong&gt; run so-called action formulas, which have access to &lt;a href=&quot;/learn/formulas/section-action.html&quot;&gt;30
brand new action functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These are some of the things you can do with a formula button:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Send a report, but only if the entered data is valid. Otherwise, show the user
an alert box.&lt;/li&gt;
  &lt;li&gt;Ask the user a series of questions, before sending a report incorporating
the entered answers.&lt;/li&gt;
  &lt;li&gt;Send multiple reports, incorporating different information, to different email
addresses.&lt;/li&gt;
  &lt;li&gt;Open a report on the user’s device, while also sending a message to the team’s
internal Slack channel. (Integration with Slack, and other third-party
services like Google Sheets, Excel and Salesforce require a third-party
service like &lt;a href=&quot;/blog/2018/05/18/zapier-video.html&quot;&gt;Zapier&lt;/a&gt;.)&lt;/li&gt;
  &lt;li&gt;Reset all fields, but only if the user first consents by pressing a button to
that effect in a message box. Then, move the user back to the first screen,
and ensure that previously-hidden text boxes are once more visible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This action formula asks the user for their name and greets them once the name
has been entered:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;What&apos;s your name?&quot;), &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Hi &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;!&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;What&apos;s your name?&quot;); &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Hi &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;!&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Formula buttons can also be used to realize the oft-requested &lt;a href=&quot;/blog/2023/08/11/calculation-buttons.html&quot;&gt;calculation
buttons&lt;/a&gt;, that only perform calculations once the user
presses a button.&lt;/p&gt;

&lt;p&gt;Action formulas are a huge new addition to Calcapp. Refer to our &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;dedicated blog
post on the subject&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2 id=&quot;alert-buttons&quot;&gt;Alert buttons&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;alert button&lt;/strong&gt; displays a message to your users, with a single button that
dismisses the message:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-new-buttons/alert.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-new-buttons/alert.png&quot; alt=&quot;Showing a message to your users&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The title, body and button label of the message are all set through
&lt;a href=&quot;/blog/2023/08/11/templates.html&quot;&gt;templates&lt;/a&gt;. That means that you can enter text strings as you
normally would, but you can also enter formula fragments, enclosed within
&lt;code&gt;&amp;lcub;&amp;lcub;&lt;/code&gt; and &lt;code&gt;&amp;rcub;&amp;rcub;&lt;/code&gt; markers.&lt;/p&gt;

&lt;p&gt;In other words, all information displayed in the alert box can be dynamic and
take into account information entered by your users and calculated by your app.&lt;/p&gt;

&lt;p&gt;For even more flexibility, consider using a &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula button&lt;/a&gt;
and the &lt;span class=&quot;link function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt; function. This formula asks the user a question
and displays the result using an alert box:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT.NUMBER&quot;&gt;PROMPT.NUMBER&lt;/span&gt;(&quot;Enter area:&quot;), &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;The cost&lt;br /&gt;is &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT.NUMBER&quot;&gt;PROMPT.NUMBER&lt;/span&gt;(&quot;Enter area:&quot;); &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;The cost&lt;br /&gt;is &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;clipboard-copy-buttons&quot;&gt;Clipboard copy buttons&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;clipboard copy button&lt;/strong&gt; copies text to the user’s clipboard. The text to
copy is entered using a template, which means that it can incorporate
information from your app.&lt;/p&gt;

&lt;p&gt;If you embed your app in a website, you need to change the HTML markup you use
slightly, otherwise copying to the clipboard won’t work.&lt;/p&gt;

&lt;p&gt;An embedded app runs in an iframe on the host page. You need to add
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allow=&quot;clipboard-write&quot;&lt;/code&gt; to the list of attributes for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iframe&lt;/code&gt; element:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;iframe seamless&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;        src=&quot;https://connect.calcapp.net/?app=abc123&quot;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;        allow=&quot;clipboard-write&quot;&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;lt;/iframe&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For even more flexibility, consider using a &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula button&lt;/a&gt;
and the &lt;span class=&quot;link function&quot; name=&quot;CLIPBOARDCOPY&quot;&gt;CLIPBOARDCOPY&lt;/span&gt; function. This formula asks the user a
question, copies the result to the clipboard and shows a banner with the text
&lt;em&gt;Copied!&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT.NUMBER&quot;&gt;PROMPT.NUMBER&lt;/span&gt;(&quot;Enter area:&quot;), &lt;span class=&quot;function&quot; name=&quot;CLIPBOARDCOPY&quot;&gt;CLIPBOARDCOPY&lt;/span&gt;(&quot;The cost is &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;); &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Copied!&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT.NUMBER&quot;&gt;PROMPT.NUMBER&lt;/span&gt;(&quot;Enter area:&quot;); &lt;span class=&quot;function&quot; name=&quot;CLIPBOARDCOPY&quot;&gt;CLIPBOARDCOPY&lt;/span&gt;(&quot;The cost is &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;);; &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Copied!&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;navigation-buttons&quot;&gt;Navigation buttons&lt;/h2&gt;

&lt;p&gt;Prior to this release, users had to press &lt;strong&gt;Next&lt;/strong&gt; in the upper-right corner of
an app to proceed to the next screen. We have seen many creative ways to direct
your users’ attention to this button, including pictures with arrows.&lt;/p&gt;

&lt;p&gt;Of course, having a button right where your fields are is often preferable. Now,
it’s finally possible.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;go forward button&lt;/strong&gt; that you don’t customize moves the user forward to the
screen you have defined in Calcapp Creator (reachable using the &lt;i class=&quot;mdi mdi-arrow-right&quot;&gt;&lt;/i&gt; button in the top-right corner of your app).&lt;/p&gt;

&lt;p&gt;Similarly, a &lt;strong&gt;go back button&lt;/strong&gt; that you don’t customize moves the user back one
screen.&lt;/p&gt;

&lt;p&gt;A go forward button can be customized to move the user forward to whatever
&lt;a href=&quot;/blog/2023/08/11/inspector-screen.html&quot;&gt;screen you select&lt;/a&gt; in the inspector. To use conditional
logic, associate a formula with the &lt;span class=&quot;link property&quot; parent-type=&quot;GoForwardButton&quot; name=&quot;Target&quot;&gt;Target&lt;/span&gt;
property that uses the &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; function.&lt;/p&gt;

&lt;p&gt;Here’s an example of such a formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;), DetailsScreen, ErrorScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;); DetailsScreen; ErrorScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above checks to see if all items of &lt;em&gt;Screen1&lt;/em&gt; are valid (&lt;a href=&quot;/blog/2023/08/11/items.html&quot;&gt;another
new feature&lt;/a&gt;). If so, the user is brought forward to &lt;em&gt;DetailsScreen&lt;/em&gt;.
Otherwise, &lt;em&gt;ErrorScreen&lt;/em&gt; is shown.&lt;/p&gt;

&lt;p&gt;You can also customize what screen to go back to using a go back button, with a
screen you select in the inspector or through a formula. However, if you select
a screen that the user has not previously visited, nothing will happen.&lt;/p&gt;

&lt;p&gt;For even more flexibility, consider using a &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula button&lt;/a&gt;
and the &lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt; functions. This
formula asks the user to confirm if they want to start over. If so, it resets
all fields and brings the user back to the first screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;CONFIRM&quot;&gt;CONFIRM&lt;/span&gt;(&quot;Start over?&quot;, Title: &quot;Question&quot;), &lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;({ App }); &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;(StartScreen))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;CONFIRM&quot;&gt;CONFIRM&lt;/span&gt;(&quot;Start over?&quot;; Title: &quot;Question&quot;); &lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;({ App });; &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;(StartScreen))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(The formula above uses a &lt;a href=&quot;/blog/2023/08/11/named-parameters.html&quot;&gt;named parameter&lt;/a&gt;, another new
feature.)&lt;/p&gt;

&lt;h2 id=&quot;browsing-the-web-printing-composing-an-email-and-more&quot;&gt;Browsing the web, printing, composing an email and more&lt;/h2&gt;

&lt;p&gt;The remaining six button types open a link in the user’s web browser, dial a
phone number for the user, compose an email or a text message (SMS), open a map
at a certain location and offer to print the current screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Print screen buttons&lt;/strong&gt; simply invoke the system print dialog, which typically
not only supports printing the current screen, but can also convert it to a PDF
file. While Calcapp can &lt;a href=&quot;/blog/2016/12/22/pdf-reports.html&quot;&gt;generate PDF files on its own&lt;/a&gt;, they are
currently limited to text. If you don’t want to use &lt;a href=&quot;/blog/2020/08/17/zapier-pdf.html&quot;&gt;a third-party service that
can generate PDF files with images&lt;/a&gt;, asking the user to use the
system print dialog may be a viable alternative.&lt;/p&gt;

&lt;p&gt;Opening links from your app &lt;a href=&quot;/blog/2017/10/29/formatted-text.html&quot;&gt;has been possible since 2017&lt;/a&gt;.
However, buttons are often more attention-grabbing than simple text links. A new
&lt;strong&gt;browse button&lt;/strong&gt; makes that possible. Also, unlike plain links, browse buttons
allow you to decide &lt;a href=&quot;/blog/2023/08/11/link-target.html&quot;&gt;where the links open&lt;/a&gt; (for instance, in a
named browser tab, or replacing your app).&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;email compose button&lt;/strong&gt; makes it possible for users to send an email using
their standard email client (a native app or a web-based service, depending on
your user’s preferences). You can pre-fill most fields, including the body and
the recipients, and you can use &lt;a href=&quot;/blog/2023/08/11/templates.html&quot;&gt;templates&lt;/a&gt; to do so (meaning that
you can easily &lt;a href=&quot;/blog/2023/08/11/better-reports.html&quot;&gt;mix pre-set text with information from your
app&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;text message compose buttons&lt;/strong&gt; and &lt;strong&gt;dial buttons&lt;/strong&gt; typically only work on
cell phones (though a desktop user with Skype installed can likely make use of a
dial button). Again, you can pre-set most text message fields and the phone
number of both buttons using templates.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;open map buttons&lt;/strong&gt; open a map using either a search query (which can
be an address), or coordinates (latitude and longitude). The user’s installed
map app is preferred. If all else fails, Google Maps is opened in the user’s web
browser.&lt;/p&gt;

&lt;p&gt;These features are also accessible through &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula buttons&lt;/a&gt;.
These are the relevant formula functions: &lt;span class=&quot;link function&quot; name=&quot;PRINTSCREEN&quot;&gt;PRINTSCREEN&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;BROWSE&quot;&gt;BROWSE&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;COMPOSE.EMAIL&quot;&gt;COMPOSE.EMAIL&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;COMPOSE.SMS&quot;&gt;COMPOSE.SMS&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;DIAL&quot;&gt;DIAL&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;OPENMAP&quot;&gt;OPENMAP&lt;/span&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 21:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/new-buttons.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/new-buttons.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Make buttons perform actions with action formulas</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Action formulas make things happen, unlike regular functions, which
  calculate values. They are our biggest new feature yet. Use them to model
  complex business logic.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Action formulas are the biggest addition to Calcapp yet. Unlike regular
formulas, which calculate values, action formulas make things happen.&lt;/p&gt;

&lt;p&gt;These are some of the things an action formula can do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Send a report, but only if the entered data is valid. Otherwise, show the user
an alert box.&lt;/li&gt;
  &lt;li&gt;Ask the user a series of questions, before sending a report incorporating
the entered answers.&lt;/li&gt;
  &lt;li&gt;Send multiple reports, incorporating different information, to different email
addresses.&lt;/li&gt;
  &lt;li&gt;Open a report on the user’s device, while also sending a message to the team’s
internal Slack channel. (Integration with Slack, and other third-party
services like Google Sheets, Excel and Salesforce require a third-party
service like &lt;a href=&quot;/blog/2018/05/18/zapier-video.html&quot;&gt;Zapier&lt;/a&gt;.)&lt;/li&gt;
  &lt;li&gt;Reset all fields, but only if the user first consents by pressing a button to
that effect in a message box. Then, move the user back to the first screen,
and ensure that previously-hidden text boxes are once more visible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To support action formulas, we have introduced &lt;a href=&quot;/learn/formulas/section-action.html&quot;&gt;30 new action
functions&lt;/a&gt;, which can do everything that a regular button can
do, and more. Action formulas also support the &lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt; operator,
which assigns values to properties. They can only be used from action formulas.&lt;/p&gt;

&lt;p&gt;This action formula asks the user for their name and greets them once the name
has been entered:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;What&apos;s your name?&quot;), &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Hi &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;!&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;What&apos;s your name?&quot;); &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Hi &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Result &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;!&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Action formulas can perform multiple actions, either one after another, or by
waiting for one to complete before invoking the next one. Action formulas can
also use conditional logic, meaning that an action is only performed if one
condition is TRUE, otherwise another action is performed. This makes it possible
to model complex business logic.&lt;/p&gt;

&lt;p&gt;These formulas can only be attached to the &lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt;
property of formula buttons. We will consider enabling action formulas elsewhere
in the future.&lt;/p&gt;

&lt;p&gt;Action formulas are not available in any of our legacy plans, meaning that you
may need to upgrade to access them. They are available in our &lt;a href=&quot;/blog/2023/08/11/plans.html&quot;&gt;2023 White Label
plans&lt;/a&gt;. Action formulas are fully functional in Calcapp Creator’s preview
sidebar, though, so you can get a feel for them, regardless of your plan.&lt;/p&gt;

&lt;h2 id=&quot;using-if-to-express-conditions&quot;&gt;Using IF to express conditions&lt;/h2&gt;

&lt;p&gt;Use a function like &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; or &lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt; to perform one
action if a condition evaluates to TRUE and another action otherwise.&lt;/p&gt;

&lt;p&gt;This formula sends an email if all fields in the app are
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;valid&lt;/span&gt; and shows a message otherwise:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;), &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, &quot;test@example.com&quot;), &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Please correct the fields first.&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;); &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; &quot;test@example.com&quot;); &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Please correct the fields first.&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;&lt;/span&gt; returns a logical array, where TRUE
indicates that a corresponding field is valid and FALSE indicates that a
corresponding field is invalid. &lt;span class=&quot;link function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt; returns TRUE only if
all those elements are TRUE, meaning that all fields are valid.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt; is a new property. &lt;a href=&quot;/blog/2023/08/11/items.html&quot;&gt;Learn more about it here.&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;running-multiple-actions&quot;&gt;Running multiple actions&lt;/h2&gt;

&lt;p&gt;An action formula can perform any number of actions. Separate actions with
&lt;span class=&quot;formula decimalpoint&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;;;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;This action formula assigns two values to two different fields and hides a text
box:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(FormGroup1); Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 10; TextBox1.&lt;span class=&quot;property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FALSE&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(FormGroup1);; Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 10;; TextBox1,&lt;span class=&quot;property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FALSE&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;By chaining together multiple actions with &lt;span class=&quot;formula decimalpoint&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;;;&lt;/span&gt;, you can
create buttons that do nothing but calculate values. For some apps, this can be
&lt;a href=&quot;/blog/2023/08/11/calculation-buttons.html&quot;&gt;an appealing alternative&lt;/a&gt; to having Calcapp calculate
values as the user types.&lt;/p&gt;

&lt;p&gt;This formula resets all fields of the app and then brings the user back to the
first screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(App); &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;(FirstScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(App);; &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;(FirstScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula assigns values to the fields of a screen named
&lt;em&gt;SecondScreen&lt;/em&gt;, before taking users to it:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;SecondScreen!Result1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FirstScreen!Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 2; SecondScreen!Result2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FirstScreen!Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; FirstScreen!Field1; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(SecondScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;SecondScreen!Result1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FirstScreen!Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 2;; SecondScreen!Result2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FirstScreen!Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; FirstScreen!Field1;; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(SecondScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If users should only be able to reach the second screen through the button, and
not by pressing &lt;strong&gt;Next&lt;/strong&gt; in the upper-right corner, ensure that the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt; property of whatever screen
precedes it is set to FALSE.&lt;/p&gt;

&lt;h2 id=&quot;waiting-for-actions-to-complete&quot;&gt;Waiting for actions to complete&lt;/h2&gt;

&lt;p&gt;Many action functions perform actions that can take some time to complete.
&lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;, for instance, sends a report through email. It does
so by asking our server to create the report and send it, which takes a second
or two.&lt;/p&gt;

&lt;p&gt;EMAILREPORT lets you perform other actions while our server is busy fulfilling
the request. This action formula asks our server to start the process, and then
immediately shows a banner:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, &quot;test@example.com&quot;); &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Sending the report, hold tight!&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; &quot;test@example.com&quot;);; &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Sending the report, hold tight!&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you want to perform an action once the report has been successfully sent, use
the &lt;span class=&quot;link function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt; function. This formula shows another banner when the
report has been sent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, &quot;test@example.com&quot;), &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;All done!&quot;)); &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Sending the report, hold tight!&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; &quot;test@example.com&quot;); &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;All done!&quot;));; &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Sending the report, hold tight!&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;handling-errors&quot;&gt;Handling errors&lt;/h2&gt;

&lt;p&gt;The AWAIT function takes three parameters: the action, the formula fragment
which is run when the action completes successfully and the formula fragment
which is run if there is a problem completing the action. Only one of the latter
two parameters must be provided, meaning that you can write a formula that only
takes action if a completing the first action fails.&lt;/p&gt;

&lt;p&gt;This formula shows an error message if sending a report fails:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, &quot;test@example.com&quot;), OnFailure: &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Could not send report: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Error.Message))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; &quot;test@example.com&quot;); OnFailure: &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Could not send report: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Error,Message))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Above, the third parameter, &lt;code&gt;OnFailure&lt;/code&gt;, &lt;a href=&quot;/blog/2023/08/11/named-parameters.html&quot;&gt;is given a
name&lt;/a&gt;. That enables us to completely leave out the second
parameter, which we don’t need. An alternative to naming the third parameter is
to use &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt; as the value for the second parameter:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, &quot;test@example.com&quot;), &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(), &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Could not send report: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Error.Message))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; &quot;test@example.com&quot;); &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(); &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;Could not send report: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Error,Message))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The third parameter has access to a special value, named &lt;code&gt;Error&lt;/code&gt;, which
has more information on the error, including an error message.&lt;/p&gt;

&lt;p&gt;If an action function does not complete successfully, and you don’t handle the
error by providing an &lt;code&gt;OnFailure&lt;/code&gt; parameter, your app will show an error
message. If you don’t want your users to see any error messages, not even your
own, you can pass &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt; as the &lt;code&gt;OnFailure&lt;/code&gt; parameter.&lt;/p&gt;

&lt;h2 id=&quot;closing-words&quot;&gt;Closing words&lt;/h2&gt;

&lt;p&gt;Formula buttons can also be used to realize the oft-requested calculation
buttons, that only perform calculations once the user presses a button. The key
addition that makes this possible is the new &lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt; operator, which
assigns values to properties. &lt;a href=&quot;/blog/2023/08/11/calculation-buttons.html&quot;&gt;Learn more about calculation
buttons&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;New functions like &lt;span class=&quot;link function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt; may be used to query users for
information. &lt;a href=&quot;/blog/2023/08/11/asking-questions.html&quot;&gt;Learn more about asking users questions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, action formulas are the culmination of a multi-year effort. Five and a
half years ago, &lt;a href=&quot;/blog/2018/01/28/action-functions.html&quot;&gt;we publicly mused about what they might look
like&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We think that the action formulas we present today are far stronger than that
early proposal. This is mostly thanks to &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;our new formula
engine&lt;/a&gt;, which was built from the ground up to support action
formulas. Now that action formulas are a reality, it is finally complete.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 20:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/action-formulas.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/action-formulas.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: An editor for tabular data</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our new data editor allows you to easily create and edit spreadsheet-like data
  tables. Data can be imported from spreadsheets through copy and paste. Use
  XLOOKUP to look up values in data tables.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Many apps created with Calcapp look up values found in data tables and present
the results to the user, rather than doing traditional math. This data can
include everything from tax brackets to information on the products offered by a
company.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;this release&lt;/a&gt;, we are introducing a spreadsheet-like
data editor for creating and updating tabular data, in the form of &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named
values&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Named values are not available in any of our legacy plans, meaning that you may
need to upgrade to access named values and the data editor. These features are
available in our &lt;a href=&quot;/blog/2023/08/11/plans.html&quot;&gt;2023 Business and White Label plans&lt;/a&gt;. They are fully
functional in Calcapp Creator’s preview sidebar, though, so you can get a feel
for them, regardless of your plan.&lt;/p&gt;

&lt;h2 id=&quot;introducing-our-new-data-editor&quot;&gt;Introducing our new data editor&lt;/h2&gt;

&lt;p&gt;This is what our new data editor looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-data-editor/data-editor.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-data-editor/data-editor.png&quot; alt=&quot;Our new data editor&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To insert data and bring up the data editor, press the new &lt;strong&gt;&lt;i class=&quot;mdi mdi-plus&quot;&gt;&lt;/i&gt; DATA&lt;/strong&gt; button in the app designer:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-data-editor/add-data-button.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-data-editor/add-data-button.png&quot; alt=&quot;A new button in the app designer that launches the data editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first row must consist of column names.&lt;/p&gt;

&lt;p&gt;To transfer data from your spreadsheet, follow these instructions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Switch to your spreadsheet.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Select the desired range.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copy the data to the clipboard (press &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;C&lt;/kbd&gt; on PC or
&lt;kbd&gt;⌘&lt;/kbd&gt;+&lt;kbd&gt;C&lt;/kbd&gt; on Mac).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Switch back to Calcapp Creator and the data editor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Select the cell in the upper left corner.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Paste the data from your spreadsheet (press &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;V&lt;/kbd&gt; or
&lt;kbd&gt;⌘&lt;/kbd&gt;+&lt;kbd&gt;V&lt;/kbd&gt; on Mac).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you click &lt;strong&gt;Save&lt;/strong&gt;, one named value per column is created:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-data-editor/named-values.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-data-editor/named-values.png&quot; alt=&quot;The named values that result from saving data in the data editor&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;editing-the-data&quot;&gt;Editing the data&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;i class=&quot;mdi mdi-plus&quot;&gt;&lt;/i&gt; DATA&lt;/strong&gt; button changes to
&lt;strong&gt;&lt;i class=&quot;mdi mdi-pencil&quot;&gt;&lt;/i&gt; DATA&lt;/strong&gt; when a compatible named
value is selected, allowing you to edit the data using the data editor.&lt;/p&gt;

&lt;p&gt;You can also change the generated formulas of the named values directly. If the
formulas look as though they could have been generated by the data editor, you
are still able to edit them using the data editor.&lt;/p&gt;

&lt;p&gt;If you need to rename a column, rename the named value in the app designer
instead of renaming the column in the data editor. If you do the latter, the
data editor will leave the named value corresponding to the old column in place,
and add a new named value with the new column name.&lt;/p&gt;

&lt;h2 id=&quot;detecting-numbers-and-dates&quot;&gt;Detecting numbers and dates&lt;/h2&gt;

&lt;p&gt;If you enter dates or numbers in the data editor, it should produce named values
whose formulas are number or date arrays, and not text arrays. That enables them
to be acted upon by functions and operators that accept numbers and dates.&lt;/p&gt;

&lt;p&gt;To that end, the data editor automatically detects numbers and dates. In order
for that to work, the language setting must match the data (which can differ
from the language of the app).&lt;/p&gt;

&lt;p&gt;Set the language by pressing the &lt;i class=&quot;mdi mdi-cog&quot;&gt;&lt;/i&gt; button:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-data-editor/data-editor-language.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-data-editor/data-editor-language.png&quot; alt=&quot;Setting the language in our new data editor&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Detected numbers appear on a blue background and detected dates appear on a pink
background.&lt;/p&gt;

&lt;p&gt;Select a range and press the &lt;i class=&quot;mdi mdi-alphabetical-variant&quot;&gt;&lt;/i&gt; button
to force Calcapp to interpret the range as text.&lt;/p&gt;

&lt;p&gt;For an example of when this might be useful, consider phone numbers, without
hyphens. Calcapp might interpret them as numbers, which is probably not what you
want — after all, there is no point in doing arithmetic with phone numbers,
and if they have leading zeroes, those should be displayed to a user. As such,
they should be interpreted as text.&lt;/p&gt;

&lt;p&gt;Likewise, press the &lt;i class=&quot;mdi mdi-auto-fix&quot;&gt;&lt;/i&gt; button to make Calcapp try
to automatically detect if the selected range represents numbers or dates.&lt;/p&gt;

&lt;h2 id=&quot;using-dedicated-screens-for-data&quot;&gt;Using dedicated screens for data&lt;/h2&gt;

&lt;p&gt;The data editor creates and works with named values that are part of the current
screen. For small tables with a few columns, that can work well.&lt;/p&gt;

&lt;p&gt;However, if your tables are large or are used from multiple screens, it’s a good
idea to move them to dedicated screens, never shown to your users.&lt;/p&gt;

&lt;p&gt;Named values, corresponding to the table with sweaters, dresses and
shorts above, could be put on a screen named &lt;em&gt;Products&lt;/em&gt;, for instance.
That would enable you to reference, say, the &lt;em&gt;Color&lt;/em&gt; named value by
writing &lt;span class=&quot;formula decimalpoint&quot;&gt;Products!Color&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Products!Color&lt;/span&gt; in a formula.&lt;/p&gt;

&lt;p&gt;To ensure that your users cannot reach these data screens, there are a few
techniques you can use:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If your app contains a list screen, you can create a navigator that is
permanently &lt;span class=&quot;link property&quot; parent-type=&quot;Navigator&quot; name=&quot;Visible&quot;&gt;invisible&lt;/span&gt; that leads to the data
screens.&lt;/li&gt;
  &lt;li&gt;If your app only consists of form screens, put the data screens after the last
user-visible form screen. Prevent your users from reaching the data screens
using the &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt; property of the last
user-visible screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have multiple data screens, create a list screen whose navigators lead to
these data screens, and make the list screen itself unreachable using the
techniques listed above.&lt;/p&gt;

&lt;h2 id=&quot;accessing-data-from-formulas&quot;&gt;Accessing data from formulas&lt;/h2&gt;

&lt;p&gt;The named values created from the &lt;em&gt;Products&lt;/em&gt; table can easily be used from
formulas. This section discusses some commonly-used formulas for processing the
data.&lt;/p&gt;

&lt;p&gt;If you want to try the formulas on this page for yourself, here’s the &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1M9YeCaXvz3_R3E3XGN44wBTSavipCyOep3Ed8uSU-ZI/edit?usp=sharing&quot;&gt;data as a
Google Sheets spreadsheet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This formula calculates the average product price:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AVERAGE&quot;&gt;AVERAGE&lt;/span&gt;(Products!Price)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AVERAGE&quot;&gt;AVERAGE&lt;/span&gt;(Products!Price)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the number of products costing more than $100:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COUNTIF&quot;&gt;COUNTIF&lt;/span&gt;(Products!Price, &quot;&amp;gt;100&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COUNTIF&quot;&gt;COUNTIF&lt;/span&gt;(Products!Price; &quot;&amp;gt;100&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the kind of the product costing the most:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Products!Kind, &lt;span class=&quot;function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(Products!Price), Products!Price))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Products!Kind; &lt;span class=&quot;function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(Products!Price); Products!Price))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the color of the product costing $129, “Black”:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(129, Products!Price, Products!Color)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(129; Products!Price; Products!Color)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To learn how XLOOKUP works, refer to &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;our documentation&lt;/span&gt;,
which contains many more formula samples.&lt;/p&gt;

&lt;h2 id=&quot;using-xlookup-with-multiple-criteria&quot;&gt;Using XLOOKUP with multiple criteria&lt;/h2&gt;

&lt;p&gt;What if we need to use multiple criteria with XLOOKUP, and not just a single
one?&lt;/p&gt;

&lt;p&gt;Let’s assume that there are three text drop-down fields, named &lt;em&gt;Kind&lt;/em&gt;, &lt;em&gt;Size&lt;/em&gt;
and &lt;em&gt;Color&lt;/em&gt;, each containing the values found in the appropriate column in the
table.&lt;/p&gt;

&lt;p&gt;This formula returns the price of the product matching the selected kind, size
and color:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE, (Kind &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Kind) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Size &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Size) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Color &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Color), Products!Price)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(TRUE; (Kind &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Kind) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Size &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Size) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Color &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Color); Products!Price)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kind&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Size&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Color&lt;/code&gt; in the formula refer to the text drop-down fields,
whereas names starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Products!&lt;/code&gt; refer to named values that are part of
the &lt;em&gt;Products&lt;/em&gt; screen.)&lt;/p&gt;

&lt;p&gt;Let’s repeat the products table here, for easy reference:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Kind&lt;/th&gt;
      &lt;th&gt;Size&lt;/th&gt;
      &lt;th&gt;Color&lt;/th&gt;
      &lt;th&gt;Price&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;

  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Blue&lt;/td&gt;
      &lt;td&gt;29&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Blue&lt;/td&gt;
      &lt;td&gt;49&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Purple&lt;/td&gt;
      &lt;td&gt;39&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Sweater&lt;/td&gt;
      &lt;td&gt;Small&lt;/td&gt;
      &lt;td&gt;Purple&lt;/td&gt;
      &lt;td&gt;29&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Dress&lt;/td&gt;
      &lt;td&gt;Small&lt;/td&gt;
      &lt;td&gt;Gray&lt;/td&gt;
      &lt;td&gt;69&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Dress&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Black&lt;/td&gt;
      &lt;td&gt;129&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Dress&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Blue&lt;/td&gt;
      &lt;td&gt;72&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Black&lt;/td&gt;
      &lt;td&gt;39&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Black&lt;/td&gt;
      &lt;td&gt;52&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Medium&lt;/td&gt;
      &lt;td&gt;Gray&lt;/td&gt;
      &lt;td&gt;49&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Shorts&lt;/td&gt;
      &lt;td&gt;Large&lt;/td&gt;
      &lt;td&gt;Purple&lt;/td&gt;
      &lt;td&gt;19&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(Kind &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Kind)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Kind &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Kind)&lt;/span&gt; in the formula above returns a logical
array, with a &lt;span class=&quot;link function&quot; name=&quot;SIZE&quot;&gt;size&lt;/span&gt; corresponding to the number of products.
Elements that are TRUE indicate that the selected kind (sweater, dress or
shorts?) matches the kind found in the table. Elements that are FALSE indicate
that there is no match.&lt;/p&gt;

&lt;p&gt;To see this, let’s assume that the user selects &lt;strong&gt;Sweater&lt;/strong&gt; from the &lt;em&gt;Kind&lt;/em&gt; text
drop-down field. If so, &lt;span class=&quot;formula decimalpoint&quot;&gt;(Kind &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Kind)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Kind &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Kind)&lt;/span&gt; returns an
array whose first four elements are TRUE, and whose remaining elements are
FALSE. That makes sense, as if you look at the data table above, the first four
products are sweaters.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(Size &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Size)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Size &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Size)&lt;/span&gt; and &lt;span class=&quot;formula decimalpoint&quot;&gt;(Color &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Color)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Color &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Products!Color)&lt;/span&gt; work similarly.&lt;/p&gt;

&lt;p&gt;When they are all put together using &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&amp;amp;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;, a logical array is
returned where TRUE elements indicate that the kind, size and color are all a
match. XLOOKUP is then instructed to find the first TRUE element in that array,
and returns the matching price from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Products!Price&lt;/code&gt; named value.&lt;/p&gt;

&lt;p&gt;To see this even more clearly, read our documentation for &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;. It contains an example that is similar to this one, but is simpler.&lt;/p&gt;

&lt;h2 id=&quot;a-walk-down-memory-lane&quot;&gt;A walk down memory lane&lt;/h2&gt;

&lt;p&gt;Looking up tabular data has always been possible with Calcapp, but has often
been needlessly difficult. &lt;a href=&quot;/blog/2015/09/26/status.html&quot;&gt;Initially&lt;/a&gt;, you had to manually convert
all data to &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; formulas. &lt;a href=&quot;/blog/2018/04/06/tabular-data-drop-downs.html&quot;&gt;In 2018&lt;/a&gt;, new
features made it possible for drop-down fields to access data, which was
converted to formulas &lt;a href=&quot;/blog/2018/04/06/column-converter.html&quot;&gt;using an app we wrote&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;In 2021&lt;/a&gt;, we introduced support for &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt; and the
&lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; function — which can do everything VLOOKUP and HLOOKUP
in Excel can do. We also introduced &lt;a href=&quot;/blog/2021/11/12/xlookup-generator.html&quot;&gt;another app that converts tabular data to
formulas&lt;/a&gt;, this time using XLOOKUP.&lt;/p&gt;

&lt;p&gt;Data from tables still had to awkwardly reside inside all formulas that used
them — they couldn’t be stored separately and simply be referenced from other
formulas. That led to data being duplicated in many formulas, making it tedious
and error-prone to update data.&lt;/p&gt;

&lt;p&gt;With the introduction of &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named values&lt;/a&gt;, you can finally store the
data separately, making data duplication a thing of the past.&lt;/p&gt;

&lt;p&gt;Once we had added support for named values, we saw an opportunity to create a
better way to manage tabular data in Calcapp. The end result is the data editor.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 19:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/data-editor.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/data-editor.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Changes to our subscription plans</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We are introducing a new set of plans at higher price points. Existing apps
  stay on the old plans at the old prices, with access to most of our new
  features. The new button types, the data editor, named values and action
  formulas require you to upgrade to a 2023 plan.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;As part of &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;our new release&lt;/a&gt;, we are introducing a new set
of plans, at higher price points.&lt;/p&gt;

&lt;p&gt;If you’re a customer today, nothing changes. You get access to most of the new
features, and what you pay stays the same.&lt;/p&gt;

&lt;p&gt;However, if you want access to most of the &lt;a href=&quot;/blog/2023/08/11/new-buttons.html&quot;&gt;new button types&lt;/a&gt;, the
&lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data editor&lt;/a&gt; or &lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;named values&lt;/a&gt;, you must upgrade to
a 2023 Business plan. If you want access to &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula buttons and action
formulas&lt;/a&gt;, you must upgrade to a 2023 White Label plan.&lt;/p&gt;

&lt;p&gt;The 2023 Business plan costs $29 per month (USD) and the 2023 White Label plan
costs $69 per month. If you go for an annual plan, you get 20 percent off.&lt;/p&gt;

&lt;p&gt;The 2023 Starter plan is still $9 per month, because we strongly feel that it
should be inexpensive to create a simple calculator (and because our Starter
customers tend to upgrade). The 2023 version does not include access to any
buttons, though.&lt;/p&gt;

&lt;p&gt;The legacy plans are no longer available when you switch plans. Existing apps
will continue to stay on them, though, and there are no plans at this time to
fully discontinue them.&lt;/p&gt;

&lt;p&gt;To upgrade to a 2023 plan, click the &lt;strong&gt;Change plan&lt;/strong&gt; button in the inspector
when you first open an app.&lt;/p&gt;

&lt;h2 id=&quot;rationale&quot;&gt;Rationale&lt;/h2&gt;

&lt;p&gt;A lot of our customers are seeing their costs go up, due to inflation and other
factors, and we’re no different. As such, we’d like to boost revenue, but
without causing our customers economic hardship, most of which are small- and
medium-sized businesses.&lt;/p&gt;

&lt;p&gt;By allowing existing apps to stay on the legacy plans, while making some of the
new features exclusive to our new plans, we are trying to thread the needle:
boost revenue from some of our existing customers, without increasing costs for
customers who choose to stay on the legacy plans.&lt;/p&gt;

&lt;p&gt;For more on our thinking, refer to what we wrote when we &lt;a href=&quot;/blog/2023/06/02/update.html&quot;&gt;announced this change
more than two months ago.&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 18:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/plans.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/plans.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Feature: Undo and redo</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Calcapp Creator now features undo and redo buttons that bring your work back
  if you inadvertently delete it.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;It’s been a long time coming, but our &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;latest release&lt;/a&gt;
finally adds support for undoing and redoing actions you take while building
apps in Calcapp Creator. Here are the new buttons in the toolbar:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-undo/top-bar.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-undo/top-bar.png&quot; alt=&quot;The undo and redo buttons in the toolbar&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All actions you take in the main designer can be undone through these buttons.
However, performing actions in other windows (such as &lt;a href=&quot;/blog/2019/04/12/private-apps.html#defining-users&quot;&gt;editing users of private
apps&lt;/a&gt; and &lt;a href=&quot;/blog/2019/04/12/paid-plans.html&quot;&gt;making changes to your subscription&lt;/a&gt;) can
typically not be undone.&lt;/p&gt;

&lt;p&gt;The new &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data editor&lt;/a&gt; provides its own undo and redo buttons.&lt;/p&gt;

&lt;p&gt;Apps other than Calcapp Creator typically store past actions in memory, a
precious commodity. For that reason, these apps often limit the number of steps
you can undo to a small number. Calcapp Creator is different, in that your
browser’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Indexed_Database_API&quot;&gt;built-in database&lt;/a&gt; is used to store large changes. For
that reason, you can undo a large number of changes, specifically 500 changes.&lt;/p&gt;

&lt;p&gt;When Calcapp &lt;a href=&quot;/blog/2015/12/10/status.html&quot;&gt;first launched as a beta in early 2016&lt;/a&gt;,
we weren’t sure if there would be a market for our new product. As such, we
prioritized adding features to adding a proper undo system. After all, why spend
time on adding support for undo if the product would not find any takers?&lt;/p&gt;

&lt;p&gt;It did find takers, and in highsight, we should have added support for undo and
redo much earlier. If you have ever lost data from inadvertently removing
something from your app, and cursed the lack of an undo button, we’re sorry it
took this long.&lt;/p&gt;

&lt;p&gt;With proper support for undo and redo, there is less of a need to regularly
&lt;a href=&quot;/blog/2017/05/25/versions.html&quot;&gt;store checkpoints of your work&lt;/a&gt;. We think that many users, ourselves
included, will find editing apps to be a less stressful experience, knowing that
if you take the wrong action, getting your work back is only a button away.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 17:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/undo.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/undo.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Autocomplete for formulas</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our new formula autocomplete system provides helpful suggestions for what you
  may want to type next. To reference a field on any screen, just type part of
  its name or label and let us do the rest.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;In the past, Calcapp Creator hasn’t offered much help when writing formulas. In
fact, writing a formula was much like writing a plain text document or email.&lt;/p&gt;

&lt;p&gt;Unlike a plain text document, though, a formula requires you to adhere to a
rigid format. Failure to do so results in error messages being displayed and,
more significantly, means that you cannot update your app.&lt;/p&gt;

&lt;p&gt;Modern editors typically offer help during the formula editing process, offering
to complete text you’re writing and providing helpful suggestions.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;As of today&lt;/a&gt;, Calcapp Creator provides one of those modern
editors. Here’s our new autocomplete feature in action:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-autocomplete/autocomplete.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-autocomplete/autocomplete.png&quot; alt=&quot;The autocomplete system in use&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you type, autocomplete tries to match your input to what you might want to
add next and displays helpful suggestions in a menu. To accept a suggestion with
your keyboard, select it using your arrow keys and press &lt;kbd&gt;Enter&lt;/kbd&gt; (not
&lt;kbd&gt;Tab&lt;/kbd&gt;).&lt;/p&gt;

&lt;p&gt;Here are some of the things Calcapp Creator now helps you add to your formulas:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Formula functions.&lt;/li&gt;
  &lt;li&gt;Screen references.&lt;/li&gt;
  &lt;li&gt;Items of the current screen.&lt;/li&gt;
  &lt;li&gt;Items of other screens (after you write the name of a screen, followed by
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;Properties (after you write the name of an item or a screen, followed by
&lt;span class=&quot;formula decimalpoint&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;,&lt;/span&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/enums.html#more-enums&quot;&gt;Enums&lt;/a&gt; (like the colors presented to you after you write
&lt;span class=&quot;formula decimalpoint&quot;&gt;Color.&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Color,&lt;/span&gt;).&lt;/li&gt;
  &lt;li&gt;Special values (like &lt;a href=&quot;/blog/2023/08/11/edit-multiple-formulas.html#referencing-the-current-item-from-a-formula&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt;&lt;/a&gt; in most formulas, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Element&lt;/code&gt; when using
the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TRUE&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FALSE&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2023/08/11/named-parameters.html&quot;&gt;Names of function parameters&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Parentheses — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;( )&lt;/code&gt; — and brackets — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ }&lt;/code&gt; (used to
construct &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The autocomplete system engages automatically. If it does not, and you’d like to
see suggestions, press &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;Space&lt;/kbd&gt; on PC, or
&lt;kbd&gt;⌘&lt;/kbd&gt;+&lt;kbd&gt;Space&lt;/kbd&gt; on Mac.&lt;/p&gt;

&lt;p&gt;Calcapp Creator understands the formulas you’re writing. What that means is that
if you write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2 + &lt;/code&gt;, you’ll be presented with functions that return numbers and
fields with numeric values, but text-returning functions and text fields won’t
be suggested.&lt;/p&gt;

&lt;p&gt;Similarly, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TRUE&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FALSE&lt;/code&gt; are only suggested if the context warrants it,
like if you’re trying to pass a value for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UseAccountingStyle&lt;/code&gt; parameter of
&lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;To reference a field (any item, really), just start typing either its name or
its label. If the field appears on a different screen, the screen name and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt;
are inserted automatically. We’ve found this to be a huge time saver.&lt;/p&gt;

&lt;p&gt;Finally, our formula documentation &lt;a href=&quot;/blog/2023/08/11/better-documentation.html#autocomplete-integration&quot;&gt;is displayed&lt;/a&gt;
when functions and properties are suggested.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 16:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/autocomplete.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/autocomplete.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Edit text properties as templates</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  All text properties can now be edited as templates. Change the text as you
  normally would in the inspector and insert formula fragments between special
  markers. This makes it much easier to edit email bodies sent by your app.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Calcapp has many text properties that can be customized using the inspector in
Calcapp Creator, including these:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;span class=&quot;link property&quot; parent-type=&quot;TextField&quot; name=&quot;Value&quot;&gt;Values&lt;/span&gt; of text fields.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;Email bodies&lt;/span&gt; of email report buttons.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;FileName&quot;&gt;File names&lt;/span&gt; of open report buttons.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;ValidationMessage&quot;&gt;Validation messages&lt;/span&gt; of fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like other &lt;a href=&quot;/blog/2017/03/23/introducing-calculated-properties.html&quot;&gt;calculated properties&lt;/a&gt;, text properties can
be set through formulas. In prior releases, this was done by clicking the &lt;strong&gt;fx&lt;/strong&gt;
button next to the property in the inspector. By using a formula, information
entered into the app by your users and calculated by your app can be made part
of the calculated value.&lt;/p&gt;

&lt;p&gt;Unfortunately, setting text properties through formulas can be awkward. Let’s
say that you want to set the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;Body&lt;/span&gt; property of
an email report button using a formula. The goal is to send an email with a body
like the following:&lt;/p&gt;

&lt;pre&gt;
Dear Sally,

The weight is 23.30 lbs.
&lt;/pre&gt;

&lt;p&gt;In prior releases, you had to use a formula like the following to achieve this:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;Dear &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Name &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;,&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;The weight is &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Weight &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; lbs.&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;Dear &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Name &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;,&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;The weight is &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Weight &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; lbs.&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;There are a few problems here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You need to know that &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; is used to join text strings together.&lt;/li&gt;
  &lt;li&gt;You need to know that you should use the &lt;span class=&quot;link function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt; formula
function to produce line breaks and paragraphs.&lt;/li&gt;
  &lt;li&gt;Producing a formula like the one above is needlessly complicated, even if you
know everything there is to know about formulas.&lt;/li&gt;
  &lt;li&gt;It inhibits the writing process, by making you focus on things other than the
text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;now&lt;/a&gt; use &lt;em&gt;templates&lt;/em&gt; instead, directly in the
inspector. A template allows you to write text as you normally do, including
blank lines, and insert formula fragments between &lt;code&gt;&amp;lcub;&amp;lcub;&lt;/code&gt; and
&lt;code&gt;&amp;rcub;&amp;rcub;&lt;/code&gt; markers.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/autocomplete.html&quot;&gt;Autocomplete&lt;/a&gt; is active when editing formula fragments, making
template editing a first-class formula editing experience.&lt;/p&gt;

&lt;p&gt;Here’s the template version of the formula above:&lt;/p&gt;

&lt;pre&gt;
Dear {{Name}},

The weight is {{Weight}} lbs.
&lt;/pre&gt;

&lt;p&gt;You can enter any formula fragments between &lt;code&gt;&amp;lcub;&amp;lcub;&lt;/code&gt; and
&lt;code&gt;&amp;rcub;&amp;rcub;&lt;/code&gt; markers, not just references to fields. These formula
fragments can be arbitrarily complex.&lt;/p&gt;

&lt;p&gt;This is what using the template looks like in the inspector, with the area where
you write the email body marked in red:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-templates/inspector-email-body.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-templates/inspector-email-body.png&quot; alt=&quot;Editing the Body property of an email report button&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above, the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;Body&lt;/span&gt; property has been selected in
the property selector (also marked in red), causing its formula to be displayed.
As you can see, a template is nothing more than an easy way to write a formula.&lt;/p&gt;

&lt;p&gt;(Templates don’t use the &lt;span class=&quot;link function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt; function. Instead, they insert
line breaks in the formula, &lt;a href=&quot;/blog/2023/08/11/grab-bag.html#insert-line-breaks-in-formulas&quot;&gt;which is now supported&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;If you prefer editing the text property as a regular formula, you need to
select the property from the property selector next to the formula field.&lt;/p&gt;

&lt;p&gt;We have removed the &lt;strong&gt;fx&lt;/strong&gt; buttons from text properties in the inspector, and
replaced them by &lt;i class=&quot;mdi mdi-code-braces&quot;&gt;&lt;/i&gt; buttons. They insert
&lt;code&gt;&amp;lcub;&amp;lcub;&lt;/code&gt; into your formulas and starts autocomplete.&lt;/p&gt;

&lt;p&gt;Templates have been enabled for all text properties in the inspector. Some text
properties, such as &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Label&quot;&gt;field labels&lt;/span&gt;, have never been in
the inspector, and still require you to edit the formula like before.&lt;/p&gt;

&lt;p&gt;There’s one property that previously was not part of the inspector and now is:
&lt;span class=&quot;link property&quot; parent-type=&quot;TextField&quot; name=&quot;Value&quot;&gt;text field values&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-templates/calculated-text.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-templates/calculated-text.png&quot; alt=&quot;Editing the Value property of text fields using the inspector&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This change makes it possible to edit text field values as templates. If you
prefer editing them as formulas instead, simply use the formula field as you
normally would.&lt;/p&gt;

&lt;p&gt;If you include line breaks in text field values, be sure to toggle &lt;strong&gt;Multiple
lines&lt;/strong&gt; in the inspector to its “on” position, so that they are displayed.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 15:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/templates.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/templates.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Access all items as a single array</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  The new Items property allows you to access all items, including fields and
  buttons, as a single array. That makes it easy to calculate the sum of all
  fields of a screen, or determine if all fields of your app are valid, with
  short, readable formulas.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;You can now access all items of a form group, a form screen or the entire app as
an &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;array&lt;/a&gt;. An item in this context is a button, a field, a text box, a
navigator, a named value or a form group.&lt;/p&gt;

&lt;p&gt;To illustrate the many uses of this new feature, let’s look at a couple of
examples:&lt;/p&gt;

&lt;h2 id=&quot;summing-all-number-fields-of-a-form-group&quot;&gt;Summing all number fields of a form group&lt;/h2&gt;

&lt;p&gt;Let’s say that the form group &lt;em&gt;Readings&lt;/em&gt; contains number fields whose values
should be summed. This formula returns the sum:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Readings)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Readings)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Calcapp interprets the formula above as this equivalent formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Readings.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Readings,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If the &lt;em&gt;Readings&lt;/em&gt; form group only consists of the number fields &lt;em&gt;Reading1&lt;/em&gt;,
&lt;em&gt;Reading2&lt;/em&gt;, &lt;em&gt;Reading3&lt;/em&gt; &lt;em&gt;Reading4&lt;/em&gt;, in that order, these two formulas are also
equivalent (and worked in &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;our previous release&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Reading1:Reading4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Reading1:Reading4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Reading1, Reading2, Reading3, Reading4 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Reading1; Reading2; Reading3; Reading4 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The chief advantage to using the Items property instead of a &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;range&lt;/a&gt; is
that you no longer need to worry about updating the formula when you add more
fields. If you add a fifth number field, &lt;em&gt;Reading5&lt;/em&gt;, that should be included in
the calculations, the two formulas above need to be updated. The first two
formulas, though, will continue working, making for fewer errors and less
error-prone maintenance work.&lt;/p&gt;

&lt;h2 id=&quot;determining-if-all-switch-fields-have-been-toggled&quot;&gt;Determining if all switch fields have been toggled&lt;/h2&gt;

&lt;p&gt;Assume that the form group &lt;em&gt;Switches&lt;/em&gt; only consists of four switch fields,
&lt;em&gt;Switch1&lt;/em&gt;, &lt;em&gt;Switch2&lt;/em&gt;, &lt;em&gt;Switch3&lt;/em&gt; and &lt;em&gt;Switch4&lt;/em&gt;, in that order. These traditional
formulas return whether they have all been toggled to their “on” positions:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switch1, Switch2, Switch3, Switch4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switch1; Switch2; Switch3; Switch4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Switch1 &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Switch2 &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Switch3 &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Switch4&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Switch1 &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Switch2 &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Switch3 &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; Switch4&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Ranges can again provide a space-saving way to express the formulas above:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switch1:Switch4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switch1:Switch4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Again, the Items property provides a better way, which does not require that the
formula is updated as switch fields are added:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switches)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switches)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;determining-if-all-fields-are-valid&quot;&gt;Determining if all fields are valid&lt;/h2&gt;

&lt;p&gt;The array of items holds the items themselves, including all their properties,
and not just their values.&lt;/p&gt;

&lt;p&gt;As such, this formula returns whether all fields of the &lt;em&gt;Switches&lt;/em&gt; form group
are &lt;span class=&quot;link property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Valid&quot;&gt;valid&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switches.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Switches,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Above, the Items property must be spelled out, as the &lt;em&gt;Switches&lt;/em&gt; form group does
not have a property named Valid, but the items of &lt;em&gt;Switches&lt;/em&gt; do.&lt;/p&gt;

&lt;h2 id=&quot;making-the-background-color-of-the-app-red-if-any-field-is-invalid&quot;&gt;Making the background color of the app red if any field is invalid&lt;/h2&gt;

&lt;p&gt;So far, we have only looked at the &lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt; property of
form groups. &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Form screens also support this property&lt;/span&gt;, meaning that any example above can work at the level of a form screen
and not just a form group.&lt;/p&gt;

&lt;p&gt;In fact, we can access &lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;all items of the entire app&lt;/span&gt;,
all at once. This formula returns whether all fields are valid:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(Your app is normally named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App&lt;/code&gt; in formulas, but can be renamed on the first
screen that is shown when you open an app in Calcapp Creator.)&lt;/p&gt;

&lt;p&gt;This formula returns whether any field is valid (meaning that a single valid
field makes the formula return TRUE):&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns whether any field is invalid, by turning all TRUE elements
of the array to FALSE, and vice versa, using &lt;span class=&quot;link function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Putting it all together, this formula returns the color red if any field is
invalid, and otherwise returns a blank value:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)), Color.Red)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)); Color,Red)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If this formula is associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;Screen&quot; name=&quot;BackgroundColor&quot;&gt;BackgroundColor&lt;/span&gt;
property of the first screen, and no other screens have their background colors
set, the end result is that the entire app turns red when a single field is
invalid.&lt;/p&gt;

&lt;h2 id=&quot;enabling-a-button-only-if-all-fields-have-been-filled-out&quot;&gt;Enabling a button only if all fields have been filled out&lt;/h2&gt;

&lt;p&gt;Let’s assume that the &lt;em&gt;DataEntry&lt;/em&gt; form screen consists of a number of fields,
all of which must be filled out in order for a button at the bottom of the
screen to become enabled.&lt;/p&gt;

&lt;p&gt;This formula, which should be associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;Button&quot; name=&quot;Enabled&quot;&gt;Enabled&lt;/span&gt;
property of the button, does just that:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(DataEntry))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(DataEntry))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If all fields need to be filled out and also &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;pass validation&lt;/span&gt;, use this formula instead:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(DataEntry)) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(DataEntry.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISDEFINED&quot;&gt;ISDEFINED&lt;/span&gt;(DataEntry)) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(DataEntry,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;accessing-only-certain-types-of-fields&quot;&gt;Accessing only certain types of fields&lt;/h2&gt;

&lt;p&gt;Most of the time, accessing the Items property works well. While it includes not
just fields, but also buttons, text boxes, navigators, named values and form
groups, most formulas involving Items can only be interpreted one way.&lt;/p&gt;

&lt;p&gt;Here’s one such formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It returns whether all fields of &lt;em&gt;Screen1&lt;/em&gt; are valid, simply because only fields
support the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; property. The meaning of that formula
may change in the future, though, if other items gain support for a property
named “Valid.”&lt;/p&gt;

&lt;p&gt;Sometimes, it’s preferable to be more specific. We also provide the following
properties:&lt;/p&gt;

&lt;p&gt;Form groups:
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;DateTimeFields&quot;&gt;DateTimeFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;NumberDropDownFields&quot;&gt;NumberDropDownFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;TextDropDownFields&quot;&gt;TextDropDownFields&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;TextFields&quot;&gt;TextFields&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Form screens:
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;DateTimeFields&quot;&gt;DateTimeFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberDropDownFields&quot;&gt;NumberDropDownFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;TextDropDownFields&quot;&gt;TextDropDownFields&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;TextFields&quot;&gt;TextFields&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;The entire app:
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;DateTimeFields&quot;&gt;DateTimeFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;NumberDropDownFields&quot;&gt;NumberDropDownFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;TextDropDownFields&quot;&gt;TextDropDownFields&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;TextFields&quot;&gt;TextFields&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;(The links above lead to our full documentation, which contains many more
examples than this blog post.)&lt;/p&gt;

&lt;p&gt;If we use the &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt; property instead of the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt; property, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Valid&lt;/code&gt; formula above looks like
this:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The meaning of this formula won’t change in the future, even if buttons gain a
property named “Valid.”&lt;/p&gt;

&lt;p&gt;Also, while &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1)&lt;/span&gt; does return whether all switch
fields of &lt;em&gt;Screen1&lt;/em&gt; have been toggled to their “on” positions, the formula may
be hard to understand. This alternative is probably clearer:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;SwitchFields&quot;&gt;SwitchFields&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Sometimes, being more specific is the only way to write a correct formula.
Consider a screen, &lt;em&gt;Screen1&lt;/em&gt;, which consists of a number of date and time
fields, as well as number fields. If we want to return the sum of all its number
fields, we may try this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Screen1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Screen1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;However, you will find that the returned sum is not correct. The reason is that
the formula above also includes the date and time fields and their values.&lt;/p&gt;

&lt;p&gt;Remember that number fields are not the only fields whose values are numbers,
that also applies to date and time fields. (&lt;span class=&quot;link property&quot; parent-type=&quot;DateTimeField&quot; name=&quot;Value&quot;&gt;Details here.&lt;/span&gt;) In effect, the formulas above return the sum of all number
fields &lt;em&gt;and&lt;/em&gt; all date and time fields of &lt;em&gt;Screen1&lt;/em&gt;, which is probably not what
we want.&lt;/p&gt;

&lt;p&gt;The solution is, again, to be more specific. This formula does what we want:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;filtering-fields&quot;&gt;Filtering fields&lt;/h2&gt;

&lt;p&gt;If we combine the Fields property with the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function, we
can apply an operation to just a few fields and not to all of them.&lt;/p&gt;

&lt;p&gt;For example, this formula returns the sum of all fields of &lt;em&gt;Screen1&lt;/em&gt; which are
considered &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;, and ignores the others:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;, Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;; Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the sum of all number fields whose values are greater than
zero:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;, Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 0))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;; Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 0))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the number of text fields whose
&lt;span class=&quot;link property&quot; parent-type=&quot;TextField&quot; name=&quot;BackgroundColor&quot;&gt;backgrounds&lt;/span&gt; are red:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;TextFields&quot;&gt;TextFields&lt;/span&gt;, Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;TextFields&quot;&gt;TextFields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;TextField&quot; name=&quot;BackgroundColor&quot;&gt;BackgroundColor&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Color.Red))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;TextFields&quot;&gt;TextFields&lt;/span&gt;; Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;TextFields&quot;&gt;TextFields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;TextField&quot; name=&quot;BackgroundColor&quot;&gt;BackgroundColor&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; Color,Red))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the largest value entered in a number field whose
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Label&quot;&gt;label&lt;/span&gt; includes the word “mandatory”:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;CONTAINS&quot;&gt;CONTAINS&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;, &quot;mandatory&quot;)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;CONTAINS&quot;&gt;CONTAINS&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;; &quot;mandatory&quot;)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Finally, this formula returns the average value entered in all number fields
whose &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Name&quot;&gt;names&lt;/span&gt; start with “F”:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AVERAGE&quot;&gt;AVERAGE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;STARTSWITH&quot;&gt;STARTSWITH&lt;/span&gt;(Screen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;, &quot;F&quot;)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AVERAGE&quot;&gt;AVERAGE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;STARTSWITH&quot;&gt;STARTSWITH&lt;/span&gt;(Screen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NumberFields&quot;&gt;NumberFields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;; &quot;F&quot;)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(All items now have &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Name&quot;&gt;names&lt;/span&gt;, &lt;a href=&quot;/blog/2023/08/11/grab-bag.html#access-the-name-of-an-item-from-a-formula&quot;&gt;which is described in
greater detail here&lt;/a&gt;.)&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 14:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/items.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/items.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Edit formulas of multiple items at the same time</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  When multiple items are checked in the app designer that use the same formula,
  this shared formula can now be edited. We also describe the new special
  formula value Item and the related performance improvements we&apos;ve made.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Calcapp Creator has always allowed you to edit multiple items (including fields
and buttons) at the same time. Simply check all the relevant items (which as of
today &lt;a href=&quot;/blog/2023/08/11/grab-bag.html#easily-check-multiple-items-in-the-app-designer&quot;&gt;is a lot easier&lt;/a&gt;) and make changes in the
inspector. You’ll find that the changes have been applied to all the relevant
checked items.&lt;/p&gt;

&lt;p&gt;For instance, let’s say that you have created 100 currency fields, but forgot to
change the currency from the default. Simply by checking those 100 items (which,
again, &lt;a href=&quot;/blog/2023/08/11/grab-bag.html#easily-check-multiple-items-in-the-app-designer&quot;&gt;is now easy&lt;/a&gt;) and selecting the desired currency
once, the changes are applied to all relevant checked items.&lt;/p&gt;

&lt;p&gt;Traditionally, that has not applied to formulas, though. Previously, if you
checked multiple items, the &lt;strong&gt;fx&lt;/strong&gt; symbols next to &lt;a href=&quot;/blog/2017/03/23/introducing-calculated-properties.html&quot;&gt;calculated
properties&lt;/a&gt; in the inspector would go away, and the
property selector and the formula field would be grayed out.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;Today&lt;/a&gt;, that changes. Now, when you check multiple items
and select a property whose formulas are either missing or are identical across
all checked items, you can simply edit the formula once, and have the changes
apply to all relevant checked items.&lt;/p&gt;

&lt;p&gt;Here’s an example app, where we want the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;
properties of all checked fields to use the same formula:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-edit-multiple-formulas/single-target.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-edit-multiple-formulas/single-target.png&quot; alt=&quot;Checking multiple items and editing their shared formula&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we are allowed to edit the shared formula of all five checked
fields.&lt;/p&gt;

&lt;p&gt;So what happens if the relevant formulas aren’t all identical? The formula field
will then display a message to that effect:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-edit-multiple-formulas/conflict-app-designer.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-edit-multiple-formulas/conflict-app-designer.png&quot; alt=&quot;The app designer, when the checked items don&apos;t share a single             formula&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To resolve the issue, just start typing in the formula field, and you’re
presented with this box:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-edit-multiple-formulas/conflict-box.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-edit-multiple-formulas/conflict-box.png&quot; alt=&quot;A box enabling you to make the formulas of the checked items             identical&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select a single formula, and that one formula will be set for all items.&lt;/p&gt;

&lt;h2 id=&quot;referencing-the-current-item-from-a-formula&quot;&gt;Referencing the current item from a formula&lt;/h2&gt;

&lt;p&gt;In the example above, all formulas reference the same switch field. What if you
instead want to reference the item the formula belongs to?&lt;/p&gt;

&lt;p&gt;Whether a field is &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;valid&lt;/span&gt; typically depends on the
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;value&lt;/span&gt; of the field. Let’s say that the relief
pressure valves in the example should not be assigned values that are less than
110 psi or greater than 200 psi.&lt;/p&gt;

&lt;p&gt;Normally, making this work for all fields is fairly easy. We simply check them
all, and enter 110 for the minimum value and 200 for the maximum value under
&lt;strong&gt;Validity&lt;/strong&gt; in the inspector.&lt;/p&gt;

&lt;p&gt;Let’s add a complicating wrinkle, though. Let’s say that having fields validated
can be annoying at times, and it is imperative that users can disable
validation. To achieve that, we add the switch field &lt;em&gt;ValidateValues&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Suddenly, we can no longer rely on the minimum and maximum values in the
inspector, now we need to determine validity using a formula.&lt;/p&gt;

&lt;p&gt;(We could use either the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; property,
or use both the &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;MinimumValue&quot;&gt;MinimumValue&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;MaximumValue&quot;&gt;MaximumValue&lt;/span&gt; properties. Here, we’ll
somewhat arbitrarily do the former.)&lt;/p&gt;

&lt;p&gt;Here’s the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; formula for &lt;em&gt;Valve1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;ValidateValues &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; ((Valve1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 110) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Valve1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 200))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;ValidateValues &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; ((Valve1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 110) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Valve1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 200))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In other words, the field is considered valid if the &lt;em&gt;ValidateValues&lt;/em&gt; switch
field is toggled to its “off” position, or if the value of &lt;em&gt;Valve1&lt;/em&gt; is greater
or equal to 110 and less than or equal to 200.&lt;/p&gt;

&lt;p&gt;Here’s the almost-identical &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; formula for &lt;em&gt;Valve2&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;ValidateValues &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; ((Valve2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 110) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Valve2 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 200))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;ValidateValues &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; ((Valve2 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 110) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Valve2 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 200))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It would appear that we can’t use a single formula for all fields,
as all the formulas need to reference the relevant field and its
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;value&lt;/span&gt;: The &lt;em&gt;Valid&lt;/em&gt; formula for
&lt;em&gt;Valve1&lt;/em&gt; must reference &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Valve1&lt;/code&gt;, the the &lt;em&gt;Valid&lt;/em&gt; formula for
&lt;em&gt;Valve2&lt;/em&gt; must reference &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Valve2&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;That’s where the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; value comes into play. All formulas associated with
items have access to this new special value, and it always references the
current item (including fields and buttons).&lt;/p&gt;

&lt;p&gt;That means that we can use a single formula for all the fields after all:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;ValidateValues &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; ((Item &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 110) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Item &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 200))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;ValidateValues &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; ((Item &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 110) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Item &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 200))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;As such, this feature enables you to conveniently edit the shared formula of all
five valve fields of the example at the same time.&lt;/p&gt;

&lt;p&gt;Note that when you access &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; from a formula, what you are accessing is the
entire item, and not just, say, a field value.&lt;/p&gt;

&lt;p&gt;That means that this formula, associated with the
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;BackgroundColor&quot;&gt;BackgroundColor&lt;/span&gt; property of a field, will work:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;Item.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;, Color.Red700)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;Item,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;; Color,Red700)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In other words, the background color of a field will turn red if the item is not
valid.&lt;/p&gt;

&lt;h2 id=&quot;related-performance-improvements&quot;&gt;Related performance improvements&lt;/h2&gt;

&lt;p&gt;We expect that this feature will lead to many more apps with identical formulas,
as they are now so easy to create and maintain. For that reason, we have done a
lot of work in Calcapp Connect (which runs your apps) to ensure that apps with a
lot of identical properties, and identical formulas, run faster and consume less
memory.&lt;/p&gt;

&lt;p&gt;This section is somewhat technical. Feel free to skip ahead to the next blog
post if you’re not interested in the details.&lt;/p&gt;

&lt;p&gt;Before, if you had 1,000 fields which all used the same
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; formula, Calcapp would needlessly create
1,000 identical so-called &lt;em&gt;property instances&lt;/em&gt; when your app was run.&lt;/p&gt;

&lt;p&gt;A property instance is necessary when a property is associated with a formula.
They consume memory, and make your apps run somewhat slower, so we try not to
create them unnecessarily. For instance, if your field is always visible, we’ll
just make a note of the fact that it’s visible, without creating a property
instance, and the same goes for all properties with unchanging values.&lt;/p&gt;

&lt;p&gt;We did create them unnecessarily before, if lots of items shared the exact same
formula. It was unnecessary, because a single property instance would have
sufficed.&lt;/p&gt;

&lt;p&gt;That’s exactly what we do now. We look at all your formulas when your app is
run, and we let items share property instances if they aren’t different from one
another. The end result is that such apps start and run faster.&lt;/p&gt;

&lt;p&gt;We’ve done that work for another reason as well: the new &lt;a href=&quot;/blog/2023/08/11/items.html&quot;&gt;Items
property&lt;/a&gt;, and related properties, make it easy to access potentially
thousands of items in one fell swoop.&lt;/p&gt;

&lt;p&gt;You can, for instance, make the background color of the app red if any
field in the entire app is invalid, by associating this formula with the
&lt;span class=&quot;link property&quot; parent-type=&quot;Screen&quot; name=&quot;BackgroundColor&quot;&gt;BackgroundColor&lt;/span&gt; property of the first screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)), Color.Red700)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;)); Color,Red700)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Colors are actually &lt;a href=&quot;/blog/2017/08/31/custom-colors.html#inheritance&quot;&gt;fairly complicated&lt;/a&gt; in Calcapp. If a
screen doesn’t have a background color set, it uses the background color from
the preceding screen, and so on. Ultimately, if no preceding screen has a
background color set, it uses the one from your theme.&lt;/p&gt;

&lt;p&gt;For various reasons, the formula above used to cause an explosion in the number
of property instances that were created, especially for very large apps. The end
result was that our powerful desktop computers in the office could barely run a
simple, but large, test app that used the technique described above.&lt;/p&gt;

&lt;p&gt;Now that property instances are shared if possible, that large test app runs
very quickly. That means that you shouldn’t run into situations where your
&lt;a href=&quot;/blog/2021/11/12/large-apps.html&quot;&gt;reasonably-sized apps&lt;/a&gt; run slowly, even if you use all the new
features of &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;this release&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 13:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/edit-multiple-formulas.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/edit-multiple-formulas.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: A grab bag of new features</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  The screens sidebar can now be resized, line breaks can be inserted into
  formulas, sliders work better on touch screens and you get more disk space
  for images. Our latest release is full of minor features such as these.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our new release contains &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;major new features&lt;/a&gt;, but also
many minor ones, that aren’t significant enough to warrant a blog post of their
own. This page collects these smaller improvements.&lt;/p&gt;

&lt;h2 id=&quot;the-screens-sidebar-can-now-become-wider&quot;&gt;The screens sidebar can now become wider&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;/blog/2017/06/25/panels-sidebar.html&quot;&gt;screens sidebar&lt;/a&gt; lists all your screens and allows you to
reorder them. For large apps in particular, it acts as an overview of your app,
allowing you to quickly move from one screen to another.&lt;/p&gt;

&lt;p&gt;The only problem was that it wasn’t resizable. Long screen labels would get
truncated, and some deeply nested screens would barely be visible.&lt;/p&gt;

&lt;p&gt;You can now easily resize the sidebar by pressing the &lt;i class=&quot;mdi mdi-arrow-expand&quot;&gt;&lt;/i&gt; button:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-grab-bag/screens-sidebar.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-grab-bag/screens-sidebar.png&quot; alt=&quot;The screens sidebar, which is now resizable&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are three widths. Press the button to toggle to the next-larger width, or
back to the standard size if the maximum width is selected.&lt;/p&gt;

&lt;h2 id=&quot;better-sliders-for-your-apps&quot;&gt;Better sliders for your apps&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2018/01/10/sliders.html&quot;&gt;Sliders&lt;/a&gt; can be enabled for number fields by toggling the appropriate
option in the inspector, and allow your users to change a value by moving a
handle:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-grab-bag/sliders.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-grab-bag/sliders.png&quot; alt=&quot;Sliders in an app&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sliders could be hard to use on touch screens, though. Specifically, sliders
would inhibit the vertical motion used for scrolling, preventing that from
happening. This would happen even if the user was sliding vertically and not
horizontally.&lt;/p&gt;

&lt;p&gt;One solution was to start the scroll motion outside of sliders, but that was an
issue for apps where most fields had sliders.&lt;/p&gt;

&lt;p&gt;Now, sliders behave more like standard sliders on iOS and Android in that they
expect you to scroll horizontally for some distance before they assume that
you’re trying to manipulate the handle of the slider. That means that if you
want to scroll vertically, sliders are much less likely to interfere with that
motion.&lt;/p&gt;

&lt;h2 id=&quot;insert-line-breaks-in-formulas&quot;&gt;Insert line breaks in formulas&lt;/h2&gt;

&lt;p&gt;You can now insert line breaks in formulas by pressing
&lt;kbd&gt;Alt&lt;/kbd&gt;+&lt;kbd&gt;Enter&lt;/kbd&gt;. This is useful when you want to enter line
breaks in literal text strings (text within quotation marks). Previously, the
only way to do this was to use the &lt;span class=&quot;link function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt; function (or to type
&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHAR&quot;&gt;CHAR&lt;/span&gt;(10)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHAR&quot;&gt;CHAR&lt;/span&gt;(10)&lt;/span&gt;).&lt;/p&gt;

&lt;p&gt;Outside of literal text, line breaks make no difference to Calcapp, but you’re
welcome to use them if you think they make your formula easier to read and edit.&lt;/p&gt;

&lt;p&gt;With the introduction of &lt;a href=&quot;/blog/2023/08/11/templates.html&quot;&gt;templates&lt;/a&gt;, you may not find yourself
needing this feature as much as you otherwise would have. When you edit a
template, simply press &lt;kbd&gt;Enter&lt;/kbd&gt; to insert a line break (which will also
cause a line break to be inserted into the corresponding formula).&lt;/p&gt;

&lt;p&gt;Here’s a user editing the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;Body&lt;/span&gt; property of an
email report button, illustrating both a template and a formula with line
breaks:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-grab-bag/inspector-email-body.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-grab-bag/inspector-email-body.png&quot; alt=&quot;Editing the Body property of an email report button&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;easily-check-multiple-items-in-the-app-designer&quot;&gt;Easily check multiple items in the app designer&lt;/h2&gt;

&lt;p&gt;Previously, if you wanted to check a range of items in Calcapp Creator (say,
Field1 through Field20), you had to individually click their check boxes.&lt;/p&gt;

&lt;p&gt;Calcapp Creator tried to ease this process by checking or unchecking all items
of a form group for you when you checked or unchecked the form group, but this
sometimes interfered with what you were trying to do.&lt;/p&gt;

&lt;p&gt;Now, you can check or uncheck ranges of items simply by pressing and holding the
&lt;kbd&gt;Shift&lt;/kbd&gt; key. Check boxes next to form groups no longer try to check or
uncheck the items of the form groups when &lt;kbd&gt;Shift&lt;/kbd&gt; is held.&lt;/p&gt;

&lt;p&gt;If you like to edit your apps on a device without a physical keyboard (like a
tablet or a cell phone), you need to press a new toggle button in the toolbar
instead:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-grab-bag/multicheck.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-grab-bag/multicheck.png&quot; alt=&quot;Checking or unchecking multiple items using a button&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;determine-if-a-field-is-persistent-from-a-formula&quot;&gt;Determine if a field is persistent from a formula&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2016/11/19/persistent-fields.html&quot;&gt;Persistent fields&lt;/a&gt; retain their values, even when your users
close your app and open it again. Make a field persistent by toggling the
&lt;strong&gt;Remember value&lt;/strong&gt; property in the inspector.&lt;/p&gt;

&lt;p&gt;This property still does not allow you to associate a formula with it. However,
you can now determine if a field is persistent from a formula, by accessing the
new read-only &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Persistent&quot;&gt;Persistent&lt;/span&gt; property.&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;action formula&lt;/a&gt; resets all fields of the app which are
not persistent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App.&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Persistent&quot;&gt;Persistent&lt;/span&gt;)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(App,&lt;span class=&quot;property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Persistent&quot;&gt;Persistent&lt;/span&gt;)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Reset buttons can be instructed not to reset persistent fields. By introducing
this new property, the &lt;span class=&quot;link function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt; action function can perform the
same feat, in conjunction with the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function.&lt;/p&gt;

&lt;h2 id=&quot;access-the-name-of-an-item-from-a-formula&quot;&gt;Access the name of an item from a formula&lt;/h2&gt;

&lt;p&gt;All items now feature a new read-only property, &lt;em&gt;Name&lt;/em&gt;, including all
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Name&quot;&gt;fields&lt;/span&gt; and &lt;span class=&quot;link property&quot; parent-type=&quot;Button&quot; name=&quot;Name&quot;&gt;buttons&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Names can be assigned manually in Calcapp Creator, but are usually assigned
automatically based on the label. When you update the label, the name is by
default also updated, as well as all formulas that reference the item.&lt;/p&gt;

&lt;p&gt;You assign names manually simply by writing a new name in the name field:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-grab-bag/field-name.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-grab-bag/field-name.png&quot; alt=&quot;Assigning a name to a field manually&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the image above, the first field would ordinarily have been named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HorizontalCoordinate&lt;/code&gt; (based on the label, with no spaces), which is quite
wordy. Above, we have renamed the field &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt;, which makes formulas much shorter.&lt;/p&gt;

&lt;p&gt;To make the name follow the label once more, just select the name and remove it
(press &lt;kbd&gt;Delete&lt;/kbd&gt; or &lt;kbd&gt;Backspace&lt;/kbd&gt;).&lt;/p&gt;

&lt;p&gt;You can now access the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Name&quot;&gt;name&lt;/span&gt; of an item from a
formula, making this formula always return TRUE:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Name&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Field&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Name&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Field&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;While that’s not terribly useful, it becomes useful in conjunction with the &lt;a href=&quot;/blog/2023/08/11/items.html&quot;&gt;new
Items property&lt;/a&gt; of &lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;form groups&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;Items&quot;&gt;form screens&lt;/span&gt; and &lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;Items&quot;&gt;the app itself&lt;/span&gt; (along with related properties, like &lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;),
along with the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function.&lt;/p&gt;

&lt;p&gt;This formula returns the sum of all fields of &lt;em&gt;FormGroup1&lt;/em&gt;, whose names start
with “Credit”:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(FormGroup1.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;STARTSWITH&quot;&gt;STARTSWITH&lt;/span&gt;(FormGroup1.&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Name&quot;&gt;Name&lt;/span&gt;, &quot;Credit&quot;)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(FormGroup1,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Items&quot;&gt;Items&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;STARTSWITH&quot;&gt;STARTSWITH&lt;/span&gt;(FormGroup1,&lt;span class=&quot;property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Fields&quot;&gt;Fields&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Name&quot;&gt;Name&lt;/span&gt;; &quot;Credit&quot;)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you devise a naming scheme for your fields, this can be a useful way of
targeting just a selection of them.&lt;/p&gt;

&lt;p&gt;These are some of the other functions, besides &lt;span class=&quot;link function&quot; name=&quot;STARTSWITH&quot;&gt;STARTSWITH&lt;/span&gt;, that
you may find useful when determining which names to include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;span class=&quot;link function&quot; name=&quot;ENDSWITH&quot;&gt;ENDSWITH&lt;/span&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;link function&quot; name=&quot;CONTAINS&quot;&gt;CONTAINS&lt;/span&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;link function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt; (advanced).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;access-the-current-item-from-a-formula&quot;&gt;Access the current item from a formula&lt;/h2&gt;

&lt;p&gt;In most formulas, you can now write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; to reference the current field,
button, text box, form group or navigator that is associated with the current
property.&lt;/p&gt;

&lt;p&gt;For instance, if the following &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; formulas are
associated with &lt;em&gt;Field1&lt;/em&gt;, both are equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 10) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 20)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 10) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 20)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;(Item &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 10) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Item &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 20)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Item &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 10) &lt;span class=&quot;binaryOperator&quot; name=&quot;CONJUNCTION&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (Item &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 20)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt; is equivalent to named item references like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1&lt;/code&gt;, meaning that it is
a reference to the item as a whole, and not just, say, a field value. That means
that you can access properties off &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt;, by writing something like
&lt;span class=&quot;formula decimalpoint&quot;&gt;Item.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Item,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;&lt;/span&gt; in a formula.&lt;/p&gt;

&lt;p&gt;This feature is primarily useful when you want many items to share the same
formula. &lt;a href=&quot;/blog/2023/08/11/edit-multiple-formulas.html&quot;&gt;This topic is explored in-depth here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;new-design-when-creating-a-new-screen&quot;&gt;New design when creating a new screen&lt;/h2&gt;

&lt;p&gt;We were never fans of the crude icon design we put together for the screen that
appears when you create a new screen:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-grab-bag/new-screen-old.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-grab-bag/new-screen-old.png&quot; alt=&quot;The old screen appearing when you create a new screen&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This vestige of the past has now been replaced with this new design:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-grab-bag/new-screen-updated.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-grab-bag/new-screen-updated.png&quot; alt=&quot;The updated screen appearing when you create a new screen&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;no-more-cell-phone-previews&quot;&gt;No more cell phone previews&lt;/h2&gt;

&lt;p&gt;The cell phone previews from the app preview sidebar of Calcapp Creator have
been removed. As you may recall, you were presented with a list of cell phone
models, and selecting one would cause the preview to be resized to approximately
match the selected model.&lt;/p&gt;

&lt;p&gt;This feature was designed at a time when there was a lot of variability between
different cell phone models, in terms of their screen sizes. Nowadays, cell
phones tend to come with large screens no matter what model you choose, making
this feature a lot less relevant.&lt;/p&gt;

&lt;p&gt;Also, we struggled to keep the list up-to-date with new models, making Calcapp
Creator look unnecessarily dated. (The oldest iPhone model we supported was an
iPhone 5 from 2012 and the newest iPhone model was the iPhone X from 2017.)&lt;/p&gt;

&lt;p&gt;Instead of updating the list, we hereby banish this feature to the dustbin of
history.&lt;/p&gt;

&lt;h2 id=&quot;more-space-for-images&quot;&gt;More space for images&lt;/h2&gt;

&lt;p&gt;The total space for images, per customer, used to be 200 MB. For image-heavy
apps, that proved too little. Every customer now has access to 1024 MB (one
gigabyte) of storage.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 12:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/grab-bag.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/grab-bag.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Use LET to avoid repetition in formulas</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  The new function LET enables you to assign names to values for use inside a
  single formula. LET can make formulas shorter and easier to read and can help
  them run faster.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;new release&lt;/a&gt; introduces support for the
&lt;span class=&quot;link function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt; function, which enables you to write shorter, more
descriptive formulas that run faster.&lt;/p&gt;

&lt;p&gt;At its core, LET makes it possible to assign names to values, which can be used
in calculations that appear to the right in the same formula.&lt;/p&gt;

&lt;p&gt;The best way to demonstrate this is with an example:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(Area &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Width &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Height, Cost &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Area &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500, Cost &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 1000)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(Area &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Width &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Height; Cost &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Area &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500; Cost &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 1000)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above first multiplies the values of the &lt;em&gt;Width&lt;/em&gt; and &lt;em&gt;Height&lt;/em&gt; fields
together and assigns the name &lt;em&gt;Area&lt;/em&gt; to the resulting value. It then multiplies
this value by 1500, assigning it the name &lt;em&gt;Cost&lt;/em&gt;. Finally, it adds 1000 to the
&lt;em&gt;Cost&lt;/em&gt; value and returns the sum.&lt;/p&gt;

&lt;p&gt;The formula above can also be written &lt;span class=&quot;formula decimalpoint&quot;&gt;(Width &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Height &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 1000&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;(Width &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Height &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 1500) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 1000&lt;/span&gt;, which is significantly shorter, but isn’t as descriptive.&lt;/p&gt;

&lt;p&gt;LET is primarily useful when you need to repeat formula fragments in a formula,
allowing you to assign a single name to the repeating part and then refer back
to it. That can make formulas shorter and make apps perform better, as it gives
Calcapp less work to do.&lt;/p&gt;

&lt;p&gt;LET is also useful when you want your formulas to be self-documenting, so that
other people can more easily determine how they work.&lt;/p&gt;

&lt;p&gt;If you need to assign names to values that are accessible from any formula, use
&lt;span class=&quot;link property&quot; parent-type=&quot;NamedValue&quot; name=&quot;Value&quot;&gt;named values&lt;/span&gt; instead (&lt;a href=&quot;/blog/2023/08/11/named-values.html&quot;&gt;introduced
here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;LET works particularly well with &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;action formulas&lt;/a&gt; (formulas
run in response to &lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;buttons being pressed&lt;/span&gt;,
another new feature). Refer to our &lt;span class=&quot;link function&quot; name=&quot;LET&quot;&gt;full documentation&lt;/span&gt; for
more on that topic.&lt;/p&gt;

&lt;h2 id=&quot;let-in-microsoft-excel&quot;&gt;LET in Microsoft Excel&lt;/h2&gt;

&lt;p&gt;Microsoft Excel &lt;a href=&quot;https://techcommunity.microsoft.com/t5/excel-blog/announcing-let/ba-p/1233572&quot;&gt;introduced support for LET back in
2020&lt;/a&gt;. &lt;a href=&quot;https://support.microsoft.com/en-us/office/let-function-34842dd8-b92b-4d3f-b325-b8b8f9908999&quot;&gt;Their version&lt;/a&gt; differs from the
Calcapp version in that you need to use &lt;span class=&quot;formula decimalpoint&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;;&lt;/span&gt; instead of
&lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt; to separate names from values.&lt;/p&gt;

&lt;p&gt;Being able to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; is a Calcapp extension, which we think makes formulas
easier to read. You can use &lt;span class=&quot;formula decimalpoint&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;;&lt;/span&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; if you
like. This may be useful if you copy and paste formulas between Excel and
Calcapp Creator.&lt;/p&gt;

&lt;h2 id=&quot;let-and-arrays&quot;&gt;LET and arrays&lt;/h2&gt;

&lt;p&gt;The values you use with LET can be of any type, including &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt;. This
formula returns the array elements that are greater than 3:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(Array &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; { 1, 2, 3, 4, 5 }, &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Array, Array &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 3))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(Array &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; { 1; 2; 3; 4; 5 }; &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Array; Array &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 3))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The version without LET would involve repeating the array:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1, 2, 3, 4, 5 }, { 1, 2, 3, 4, 5 } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 3)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1; 2; 3; 4; 5 }; { 1; 2; 3; 4; 5 } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 3)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;You can also filter an array without repeating it, and without using LET, using
a feature specific to Calcapp:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1, 2, 3, 4, 5 }, Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 3)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1; 2; 3; 4; 5 }; Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 3)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Be sure to check out our &lt;span class=&quot;link function&quot; name=&quot;LET&quot;&gt;full documentation&lt;/span&gt; for more on LET,
including lots of formula samples.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 11:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/let-function.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/let-function.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Named values</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Named values allow you to assign names to values returned from formulas.
  Unlike hidden fields, named values can represent anything a formula can
  return, including screens and arrays.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;new release&lt;/a&gt; adds support for &lt;em&gt;named values&lt;/em&gt;. Like a
&lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden field&lt;/a&gt;, a named value can be referenced from any formula.
Unlike a hidden field, a named value can represent anything, including screens
and arrays. Named values are normally hidden from the user.&lt;/p&gt;

&lt;p&gt;Create a named value by creating a new field and selecting &lt;strong&gt;Named value&lt;/strong&gt; from
the field drop-down in the inspector:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-named-values/named-value-selection.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-named-values/named-value-selection.png&quot; alt=&quot;Creating a named value using the field drop-down in the inspector&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is what the inspector looks like when a named value is selected:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-named-values/named-value-inspector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-named-values/named-value-inspector.png&quot; alt=&quot;The inspector showing properties for a named value&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To determine the &lt;span class=&quot;link property&quot; parent-type=&quot;NamedValue&quot; name=&quot;Value&quot;&gt;value&lt;/span&gt; represented by a named
value, press the &lt;strong&gt;fx&lt;/strong&gt; button next to &lt;strong&gt;Value&lt;/strong&gt; and edit the formula.&lt;/p&gt;

&lt;p&gt;You can use named values to cut down on repetition in formulas. Instead of
duplicating a formula fragment in many formulas, use a named value instead and
reference the named value from the formulas by writing its name. That makes
formulas easier to read and can boost performance too, as it gives Calcapp less
to do.&lt;/p&gt;

&lt;p&gt;If you have experience with traditional programming, you can think of a named
value as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Variable_(computer_science)&quot;&gt;variable&lt;/a&gt;. While a variable only changes when
you explicitly assign a value to it, a named value updates automatically when
the values its formula relies on change.&lt;/p&gt;

&lt;p&gt;If you want to name values for use in a single formula, consider using the
&lt;span class=&quot;link function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt; function instead (introduced &lt;a href=&quot;/blog/2023/08/11/let-function.html&quot;&gt;in this post&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;For more detailed information on named values, including lots of sample
formulas, refer to our &lt;span class=&quot;link property&quot; parent-type=&quot;NamedValue&quot; name=&quot;Value&quot;&gt;full documentation&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Named values are not available in any of our legacy plans, meaning that you may
need to upgrade to access this feature. They are available in our &lt;a href=&quot;/blog/2023/08/11/plans.html&quot;&gt;2023 Business
and White Label plans&lt;/a&gt;. They are fully functional in Calcapp Creator’s
preview sidebar, though, so you can get a feel for them, regardless of your
plan.&lt;/p&gt;

&lt;h2 id=&quot;named-values-versus-hidden-fields&quot;&gt;Named values versus hidden fields&lt;/h2&gt;

&lt;p&gt;We introduced &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden fields&lt;/a&gt; back in 2016, to solve the same
issue solved by named values. Hidden fields are number fields, switch fields or
text fields that are invisible to the user. They are not invisible to other
formulas, though, and as a result can be used to cut down on formula repetition
and make formulas easier to read.&lt;/p&gt;

&lt;p&gt;Since their introduction, Calcapp has gained the ability to reference more
things than numbers, logical values (TRUE or FALSE) and text strings. In
particular, our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;last big release&lt;/a&gt; made it possible to
refer to things such as screens, fields, buttons and arrays.&lt;/p&gt;

&lt;p&gt;Consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;NumberField1&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;NumberField1&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you assign this formula to a hidden number field and reference it from
another formula, the &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;value&lt;/span&gt; of the field (say,
4) is returned, because number field values expect their formulas to represent
numbers.&lt;/p&gt;

&lt;p&gt;If you instead assign the formula to a named value and reference it from another
formula, the actual field is returned, including its value and all its other
properties, like &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;To see the difference, let’s assume that the named value is named &lt;em&gt;ActiveField&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This formula adds 2 to the &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;value&lt;/span&gt; of
&lt;em&gt;ActiveField&lt;/em&gt;, because &lt;span class=&quot;link binaryOperator&quot; name=&quot;+&quot;&gt;+&lt;/span&gt; expects both values to be numbers:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;ActiveField &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;ActiveField &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns 2 if the active field is visible, and 4 otherwise:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ActiveField.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;, 2, 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ActiveField,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;; 2; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;While &lt;span class=&quot;formula decimalpoint&quot;&gt;ActiveField &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;ActiveField &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt; would have worked if &lt;em&gt;ActiveField&lt;/em&gt; had
been a hidden number field, &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ActiveField.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;, 2, 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ActiveField,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;; 2; 4)&lt;/span&gt;
only works if &lt;em&gt;ActiveField&lt;/em&gt; is a named value.&lt;/p&gt;

&lt;p&gt;The reason is that &lt;em&gt;ActiveField&lt;/em&gt;, as a named value, represents the field in its
entirety, and not just its value. For that reason, properties like
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; can be accessed.&lt;/p&gt;

&lt;p&gt;Finally, consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ActiveField.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ ActiveField }, &quot;test@example.com&quot;), &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Could not send report.&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ActiveField,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ ActiveField }; &quot;test@example.com&quot;); &lt;span class=&quot;function&quot; name=&quot;BANNER&quot;&gt;BANNER&lt;/span&gt;(&quot;Could not send report.&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula is an action formula, and must be associated with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt; property of a formula button. (&lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;Action
formulas are new to this release.&lt;/a&gt;) It only sends a report if
the active field is &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;valid&lt;/span&gt;, and otherwise
&lt;span class=&quot;link function&quot; name=&quot;BANNER&quot;&gt;displays an error message&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;The sent report includes only the active field and its value. Again, this works
because &lt;em&gt;ActiveField&lt;/em&gt; is a reference to the field itself, and not only to its
value.&lt;/p&gt;

&lt;h2 id=&quot;named-values-hidden-fields-and-the-assignment-operator&quot;&gt;Named values, hidden fields and the assignment operator&lt;/h2&gt;

&lt;p&gt;The new &lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt; operator may be used to assign values to properties
from &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;action formulas&lt;/a&gt;. This formula calculates a value which
it then assigns to &lt;em&gt;Field1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; 42 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Field2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; 42 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Field2&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This action formula hides a text box if &lt;em&gt;Field1&lt;/em&gt; is less than ten:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 10, TextBox1.&lt;span class=&quot;property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FALSE)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 10; TextBox1,&lt;span class=&quot;property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; FALSE)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Assume that we have two formula buttons that move the user to different screens
(through the &lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt; action function). Let’s also assume that
we want to keep track of what button the user pressed by storing a text string.&lt;/p&gt;

&lt;p&gt;Where should we store the text string? You may think that a named value would be
the appropriate place, but named values cannot be used with &lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt;.
In fact, named values can only determine their values through formulas.&lt;/p&gt;

&lt;p&gt;Instead, you need to use a hidden text field. If we name it &lt;em&gt;SelectedButton&lt;/em&gt;,
this is the formula we need for one of the buttons:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;SelectedButton &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;edit&quot;; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;SelectedButton &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;edit&quot;;; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditScreen)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;named-values-tabular-data-and-arrays&quot;&gt;Named values, tabular data and arrays&lt;/h2&gt;

&lt;p&gt;As named values can represent anything, they can also represent data in the form
of &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt;. That capability makes it possible to create and update data
separately from other formulas.&lt;/p&gt;

&lt;p&gt;Assume that the following formula is associated with the named value &lt;em&gt;Name&lt;/em&gt;, a
part of the screen &lt;em&gt;Employee&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &quot;Bill&quot;, &quot;Sally&quot;, &quot;Amy&quot;, &quot;Joe&quot; }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &quot;Bill&quot;; &quot;Sally&quot;; &quot;Amy&quot;; &quot;Joe&quot; }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Further, assume that the following formula is associated with the named value
&lt;em&gt;Salary&lt;/em&gt;, residing on the same screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 40000, 55000, 70000, 65000 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 40000; 55000; 70000; 65000 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first element of &lt;em&gt;Name&lt;/em&gt; corresponds to the first element of &lt;em&gt;Salary&lt;/em&gt;, the
second element of &lt;em&gt;Name&lt;/em&gt; corresponds to the second element of &lt;em&gt;Salary&lt;/em&gt;, etc. In
other words, the two named values correspond to columns in a data table, holding
the salaries of four employees.&lt;/p&gt;

&lt;p&gt;Using these two named values, the following formula looks up the salary of an
employee whose name is stored in the &lt;em&gt;Name&lt;/em&gt; field:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(Name, Employees!Name, Employees!Salary)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(Name; Employees!Name; Employees!Salary)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The following formula returns the average salary of all employees:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AVERAGE&quot;&gt;AVERAGE&lt;/span&gt;(Employees!Salary)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AVERAGE&quot;&gt;AVERAGE&lt;/span&gt;(Employees!Salary)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the number of employees who earn more than $50,000 per
year:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COUNTIF&quot;&gt;COUNTIF&lt;/span&gt;(Employees!Salary, &quot;&amp;gt;50000&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COUNTIF&quot;&gt;COUNTIF&lt;/span&gt;(Employees!Salary; &quot;&amp;gt;50000&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Finally, this formula looks up the name of the employee with the highest salary:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Employees!Name, &lt;span class=&quot;function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(Employees!Salary), Employees!Salary))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Employees!Name; &lt;span class=&quot;function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(Employees!Salary); Employees!Salary))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Without named values, both arrays would have had to be duplicated in all these
formulas.&lt;/p&gt;

&lt;p&gt;Having named values reference arrays is so useful that we built a major feature
around them: our new &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data editor&lt;/a&gt;, which allows data to be edited
in the same way as a spreadsheet. Under the hood, the data editor creates and
updates named values, corresponding to columns in the tabular data.&lt;/p&gt;

&lt;h2 id=&quot;using-named-values-to-create-aliases&quot;&gt;Using named values to create aliases&lt;/h2&gt;

&lt;p&gt;Named values can be used to create aliases, or alternative names, for names in
Calcapp that are perhaps overly long.&lt;/p&gt;

&lt;p&gt;The action function &lt;span class=&quot;link function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt; allows the format of the sent
report to be given as the second parameter. Here’s a formula that requests plain
text:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt;({ App}, OpenReportFormat.PlainText)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt;({ App}; OpenReportFormat,PlainText)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you find yourself using the OPENREPORT function many times, you may want to
consider creating an alias for &lt;span class=&quot;formula decimalpoint&quot;&gt;OpenReportFormat.PlainText&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;OpenReportFormat,PlainText&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Assume that this formula is associated with the named value &lt;em&gt;Plain&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;OpenReportFormat.PlainText&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;OpenReportFormat,PlainText&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;With this named value, the OPENREPORT formula above can be made shorter:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt;({ App}, Plain)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt;({ App}; Plain)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;making-named-values-visible&quot;&gt;Making named values visible&lt;/h2&gt;

&lt;p&gt;Named values are normally hidden. However, you can make them visible by toggling
their &lt;span class=&quot;link property&quot; parent-type=&quot;NamedValue&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property. This is useful when you’re
testing your app, as it makes it possible to inspect the values used from your
formulas. As there is little other reason to make named values visible, their
appearance cannot be changed.&lt;/p&gt;

&lt;p&gt;You are welcome to use a formula to determine whether a named value is visible.
That can be used to add a “debug mode” to your app, which can be enabled from a
Settings screen (perhaps only visible if you, the app author, is using the app,
through &lt;span class=&quot;link property&quot; parent-type=&quot;App&quot; name=&quot;UserEmailAddress&quot;&gt;UserEmailAddress&lt;/span&gt; or &lt;span class=&quot;link function&quot; name=&quot;USERHASTAG&quot;&gt;USERHASTAG&lt;/span&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2017/04/03/debug-mode.html&quot;&gt;This tip from 2017&lt;/a&gt; discusses adding a debug mode to make &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden
fields&lt;/a&gt; visible, but it is equally applicable to named values.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 10:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/named-values.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/named-values.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Customizable link targets</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Browse buttons and the BROWSE function allow you to determine if links
  open in a new web browser window or tab or replace the app. An app-wide
  default setting can also be changed, which also affects where text box links
  open.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Calcapp has supported adding website links since 2017, when we &lt;a href=&quot;/blog/2017/10/29/formatted-text.html&quot;&gt;added support
for formatted text&lt;/a&gt; to text boxes. &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;Our new
release&lt;/a&gt; adds two more ways to link to websites: &lt;a href=&quot;/blog/2023/08/11/new-buttons.html&quot;&gt;browse
buttons&lt;/a&gt; and the &lt;span class=&quot;link function&quot; name=&quot;BROWSE&quot;&gt;BROWSE&lt;/span&gt; action function both open
the user’s web browser at a certain address.&lt;/p&gt;

&lt;p&gt;When a link is opened on the web, the default behavior is for it to open in the
current web browser window or tab. &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target&quot;&gt;HTML allows this behavior to be
customized&lt;/a&gt;, so that a link is opened in a new tab or window.
This is known as the &lt;em&gt;target&lt;/em&gt; of the link.&lt;/p&gt;

&lt;p&gt;If the current page is running as part of a so-called &lt;em&gt;iframe&lt;/em&gt; (which can be
seen as a rectangular area of a host page that houses a different web page),
HTML allows the link to replace the host page, instead of the default behavior,
which is to just replace the current page residing in that rectangular box.&lt;/p&gt;

&lt;p&gt;This is relevant, as apps created with Calcapp can be embedded in your website,
and iframes are used to make that happen. Read on to learn more about how link
targets are changing for embedded apps.&lt;/p&gt;

&lt;h2 id=&quot;browse-buttons-and-the-browse-function&quot;&gt;Browse buttons and the BROWSE function&lt;/h2&gt;

&lt;p&gt;The new browse button allows this behavior to be customized. Here are the
inspector properties shown when a browse button is selected, with the new target
property highlighted:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-link-target/browse-button-inspector-link-target.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-link-target/browse-button-inspector-link-target.png&quot; alt=&quot;The link target property in the inspector for a browse button&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the available options:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-link-target/browse-button-inspector-link-target-menu.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-link-target/browse-button-inspector-link-target-menu.png&quot; alt=&quot;The options for the link target property of browse buttons&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(The names have intentionally been chosen to match the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target&lt;/code&gt; attribute of
HTML &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target&quot;&gt;documented here&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;This is what the options mean:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Value&lt;/th&gt;
      &lt;th&gt;Meaning&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;

  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Default&lt;/td&gt;
      &lt;td&gt;
        Use the app-wide link target setting. See below for more information.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Self&lt;/td&gt;
      &lt;td&gt;
        The link replaces the app (and just the app, if it has been embedded
        in another website.)
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Blank&lt;/td&gt;
      &lt;td&gt;
        The link is opened in a new web browser tab or window.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Parent&lt;/td&gt;
      &lt;td&gt;
        The link replaces the page hosting the iframe element. If the app isn&apos;t
        embedded, the link is opened in a new web browser tab or window.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Top&lt;/td&gt;
      &lt;td&gt;
        The link replaces the top-most page hosting the iframe element. This is
        only different from &lt;strong&gt;Parent&lt;/strong&gt; if the iframe hosting the
        app is itself hosted in another iframe.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;Named target&lt;/td&gt;
      &lt;td&gt;
        The link is opened in a web browser window or tab with a certain name
        (which is provided separately in the inspector). If a different link has
        previously been opened with a target name matching this link&apos;s target
        name, this link replaces the other link in the other tab or window.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The target property is a calculated property, meaning that it can be set through
a formula. Refer to our &lt;span class=&quot;link property&quot; parent-type=&quot;BrowseButton&quot; name=&quot;Target&quot;&gt;documentation for that property&lt;/span&gt; for more information.&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;BROWSE&quot;&gt;BROWSE&lt;/span&gt; function also allows the target to be set. The linked
page has more information on how to use the function.&lt;/p&gt;

&lt;p&gt;(BROWSE is an action function and must be run through a &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula
button&lt;/a&gt;.)&lt;/p&gt;

&lt;h2 id=&quot;default-behavior&quot;&gt;Default behavior&lt;/h2&gt;

&lt;p&gt;Previously, all links opened in a new web browser window or tab (corresponding
to the new &lt;strong&gt;Blank&lt;/strong&gt; option). This made a lot of sense for stand-alone apps,
which would otherwise have been replaced by the opened link.&lt;/p&gt;

&lt;p&gt;However, this behavior caused issues for embedded apps. Links that were part of
the app always opened in a new window or tab, which often was not the behavior
used by the links on the host page. From a user’s perspective, the difference in
behavior made little sense.&lt;/p&gt;

&lt;p&gt;With our our new release, the default behavior differs depending on if the app
is running stand-alone or embedded in a host page. For stand-alone apps, the
default behavior remains for links to open in a new window or tab (the &lt;strong&gt;Blank&lt;/strong&gt;
option above). For embedded apps, the new default behavior is for links to
replace the top-most host page (the &lt;strong&gt;Top&lt;/strong&gt; option above).&lt;/p&gt;

&lt;p&gt;(Whether an app is considered to be embedded is related to how it’s used and not
to the plan it’s on.)&lt;/p&gt;

&lt;p&gt;The default behavior can be customized in the inspector when the start screen is
shown (press the &lt;i class=&quot;mdi mdi-arrow-left&quot;&gt;&lt;/i&gt; button until you reach it):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-link-target/default-setting.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-link-target/default-setting.png&quot; alt=&quot;The default link target in the inspector for the start screen&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only way to determine where text box links open is through this setting.
Browse buttons and the &lt;span class=&quot;link function&quot; name=&quot;BROWSE&quot;&gt;BROWSE&lt;/span&gt; function default to using this
setting, but allow the behavior to be customized on a per-button or per-function
basis.&lt;/p&gt;

&lt;p&gt;Newly-created apps use the new default behavior, described above. However, apps
created using a prior version of Calcapp retain the old behavior of all links
opening in a new window or tab, meaning that this setting must be changed
manually if you’d prefer the new behavior.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 09:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/link-target.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/link-target.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Improvements to reports</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  The bodies of sent emails can now be edited as templates, making for a more
  comfortable experience. The fields to include can be set visually. Most
  report-related properties can now be set through formulas, and report-related
  action functions offer lots of flexibility.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;One of the most used button types is email report buttons, which enable your
apps to send emails with the information collected and calculated by your app.
When we &lt;a href=&quot;/blog/2016/10/18/reporting-email.html&quot;&gt;first introduced the feature in 2016&lt;/a&gt;, you were
limited to sending your app’s field values.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2021/11/12/formula-driven-emails.html&quot;&gt;In 2021&lt;/a&gt;, we introduced the new
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;Body&lt;/span&gt; property, enabling you to leave out field
values altogether and fully set the body using a formula.&lt;/p&gt;

&lt;p&gt;That setup now becomes the default. When you create a new email report button,
it will be configured to not include field values. Instead, it will present an
email editor very much like what you’d find in an email client, complete with
the ability to set recipients, a subject line and a body.&lt;/p&gt;

&lt;h2 id=&quot;editing-the-body-of-your-email&quot;&gt;Editing the body of your email&lt;/h2&gt;

&lt;p&gt;The email body in the inspector now expands in width when it becomes focused,
more closely mimicking a traditional email client and allowing you to write
more comfortably.&lt;/p&gt;

&lt;p&gt;More important is the fact that the body, and all other text properties, are now
&lt;a href=&quot;/blog/2023/08/11/templates.html&quot;&gt;templates&lt;/a&gt;. What that means is that you can easily insert formula
fragments, simply by placing them between &lt;code&gt;&amp;lcub;&amp;lcub;&lt;/code&gt; and
&lt;code&gt;&amp;rcub;&amp;rcub;&lt;/code&gt; markers.&lt;/p&gt;

&lt;p&gt;Here’s an example:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-reports/inspector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-reports/inspector.png&quot; alt=&quot;Editing the Body property of an email report button&quot; class=&quot;medium-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Previously, you would have had to associate a formula like the following with
the the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;Body&lt;/span&gt; property of the email report
button:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;Dear &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Name &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;,&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;We hope this email finds you well…&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;Dear &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Name &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;,&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;We hope this email finds you well…&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/autocomplete.html&quot;&gt;Autocomplete&lt;/a&gt; is active when editing formula fragments, making
template editing a first-class formula editing experience.&lt;/p&gt;

&lt;p&gt;You’re not limited to referencing fields within the &lt;code&gt;&amp;lcub;&amp;lcub;&lt;/code&gt;
and &lt;code&gt;&amp;rcub;&amp;rcub;&lt;/code&gt; markers, you can use arbitrarily complicated
calculations.&lt;/p&gt;

&lt;h2 id=&quot;including-field-values&quot;&gt;Including field values&lt;/h2&gt;

&lt;p&gt;If you want to include field values, be sure to select &lt;strong&gt;Include this screen’s
fields&lt;/strong&gt;, &lt;strong&gt;Include all fields&lt;/strong&gt; or &lt;strong&gt;Include specific fields&lt;/strong&gt; from the
drop-down that initially reads &lt;strong&gt;Don’t include fields&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you select &lt;strong&gt;Include specific fields&lt;/strong&gt;, a property labeled &lt;strong&gt;Included
fields&lt;/strong&gt; appears, along with a new pen button for determing what fields to
include visually:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-reports/pen-button.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-reports/pen-button.png&quot; alt=&quot;A pen button allowing you to select fields&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you press this button, &lt;a href=&quot;/blog/2023/08/11/inspector-fields.html&quot;&gt;this box appears&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-reports/fields-selection.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-reports/fields-selection.png&quot; alt=&quot;Determining what fields to include in a report&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you’re done selecting your fields, press &lt;strong&gt;Next&lt;/strong&gt; to change the order of
the fields in the report:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-reports/fields-order.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-reports/fields-order.png&quot; alt=&quot;Determining the order of the fields to include in a report&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selecting what fields to include &lt;a href=&quot;/blog/2021/11/12/reports.html&quot;&gt;was introduced in 2021&lt;/a&gt;, but
required the formula of the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;IncludedFields&lt;/span&gt;
property to be edited manually. We think that having a graphical way to
determine what fields to include makes the feature accessible to many more users
(and is easier to use even if you’re a formula savant).&lt;/p&gt;

&lt;h2 id=&quot;more-properties-are-now-calculated-properties&quot;&gt;More properties are now calculated properties&lt;/h2&gt;

&lt;p&gt;Many of the properties related to email report buttons, open report buttons and
server relay buttons were previously regular properties, meaning that you
couldn’t associate them with formulas. That meant that the only way to allow
your users to, say, determine if a CSV report or a PDF report should be sent was
to include multiple buttons.&lt;/p&gt;

&lt;p&gt;That is mostly a thing of the past with this release, which converts most
properties to true &lt;a href=&quot;/blog/2017/03/23/introducing-calculated-properties.html&quot;&gt;calculated properties&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the complete list of properties you can now associate with formulas:&lt;/p&gt;

&lt;p&gt;Email report buttons:
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;FieldInclusion&quot;&gt;FieldInclusion&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Format&quot;&gt;Format&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludeBlankValues&quot;&gt;IncludeBlankValues&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludeHiddenFields&quot;&gt;IncludeHiddenFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludeScreenLabels&quot;&gt;IncludeScreenLabels&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;ResetFields&quot;&gt;ResetFields&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;SeparateScreens&quot;&gt;SeparateScreens&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Open report buttons:
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;FieldInclusion&quot;&gt;FieldInclusion&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;Format&quot;&gt;Format&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;IncludeBlankValues&quot;&gt;IncludeBlankValues&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;IncludeHiddenFields&quot;&gt;IncludeHiddenFields&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;IncludeScreenLabels&quot;&gt;IncludeScreenLabels&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;ResetFields&quot;&gt;ResetFields&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;SeparateScreens&quot;&gt;SeparateScreens&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Server relay buttons:
&lt;span class=&quot;link property&quot; parent-type=&quot;ServerRelayButton&quot; name=&quot;Address&quot;&gt;Address&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;ServerRelayButton&quot; name=&quot;FieldInclusion&quot;&gt;FieldInclusion&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;ServerRelayButton&quot; name=&quot;IncludeBlankValues&quot;&gt;IncludeBlankValues&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;ServerRelayButton&quot; name=&quot;IncludeHiddenFields&quot;&gt;IncludeHiddenFields&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;ServerRelayButton&quot; name=&quot;ResetFields&quot;&gt;ResetFields&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Let’s enable a user to determine if a CSV or PDF report should be sent: Assume
that there’s a text drop-down field named &lt;em&gt;FormatSelection&lt;/em&gt;, with the options
“CSV” and “PDF”, as well as an email report button.&lt;/p&gt;

&lt;p&gt;Associate this formula with the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Format&quot;&gt;Format&lt;/span&gt;
property of the email report button:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(FormatSelection, &quot;CSV&quot;, EmailReportFormat.Dsv, &quot;PDF&quot;, EmailReportFormat.Pdf)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(FormatSelection; &quot;CSV&quot;; EmailReportFormat,Dsv; &quot;PDF&quot;; EmailReportFormat,Pdf)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;report-related-action-functions&quot;&gt;Report-related action functions&lt;/h2&gt;

&lt;p&gt;Our new release introduces &lt;a href=&quot;/learn/formulas/section-action.html&quot;&gt;30 new action functions&lt;/a&gt;,
which can be used from formulas associated with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt; property of
&lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula buttons&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These are the new functions related to reports:
&lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT.CSV&quot;&gt;EMAILREPORT.CSV&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT.DSV&quot;&gt;EMAILREPORT.DSV&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT.TSV&quot;&gt;EMAILREPORT.TSV&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;OPENREPORT.CSV&quot;&gt;OPENREPORT.CSV&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;OPENREPORT.DSV&quot;&gt;OPENREPORT.DSV&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;OPENREPORT.TSV&quot;&gt;OPENREPORT.TSV&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;RELAY&quot;&gt;RELAY&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;There is nothing a report button can do that the functions above
cannot. All features are accessible, and we have even introduced &lt;a href=&quot;/blog/2023/08/11/named-parameters.html&quot;&gt;named
parameters&lt;/a&gt; to make the new functions easy to use.&lt;/p&gt;

&lt;p&gt;Action formulas make it possible to do report-related things that were
previously unimaginable. This formula collects an email address through a prompt
and then sends an email to that address:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Enter the email address:&quot;), &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, Result, SubjectLine: &quot;The latest readings&quot;, Body: &quot;Refer to the readings below:&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Enter the email address:&quot;); &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; Result; SubjectLine: &quot;The latest readings&quot;; Body: &quot;Refer to the readings below:&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Through action formulas, a single button can send different reports to
different addresses, while also &lt;span class=&quot;link function&quot; name=&quot;RELAY&quot;&gt;sending a message&lt;/span&gt;
to the internal Slack channel, &lt;span class=&quot;link function&quot; name=&quot;RESET&quot;&gt;resetting fields&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;moving the user to a different screen&lt;/span&gt;. Refer to
&lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;our dedicated blog post&lt;/a&gt; for an expanded discussion and
many sample formulas.&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt;
functions can be configured to send field values as delimiter-separated
values (including CSV), but &lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT.DSV&quot;&gt;EMAILREPORT.DSV&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;OPENREPORT.DSV&quot;&gt;OPENREPORT.DSV&lt;/span&gt; offer &lt;a href=&quot;/blog/2021/11/12/csv.html&quot;&gt;more options for configuring these
values&lt;/a&gt;. &lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT.CSV&quot;&gt;EMAILREPORT.CSV&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT.TSV&quot;&gt;EMAILREPORT.TSV&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;OPENREPORT.CSV&quot;&gt;OPENREPORT.CSV&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;OPENREPORT.TSV&quot;&gt;OPENREPORT.TSV&lt;/span&gt; are
convenience functions that are pre-configured to use commas or tabs as
separators.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 08:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/better-reports.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/better-reports.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Sample app: Edit tags using action formulas</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  This sample app allows users to edit tags, which are often used on online
  marketplaces like eBay. The app demonstrates many new Calcapp features, like
  action formulas, the LET function, navigation buttons and clipboard copy
  buttons.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Sample%3A%20Tag%20editor
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on this sample app ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;We &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;boldly claim&lt;/a&gt; that action formulas are the biggest addition
to Calcapp ever, and that they enable you to create apps that would not have
been possible without them. With this new sample app, we put that claim to the
test.&lt;/p&gt;

&lt;p&gt;There are various online marketplaces that allow you to post products and
describe them using text tags, such as &lt;a href=&quot;https://www.ebay.com&quot;&gt;eBay&lt;/a&gt;. These tags are usually
limited not only in terms of how many you can use, but also in terms of their
character lengths. It is often to a seller’s benefit to use as many tags as
possible, and to put as much information as possible in them.&lt;/p&gt;

&lt;p&gt;However, sometimes these online marketplaces offer poor tools for creating and
editing tags. With that problem as our inspiration, we set out to create an app
that serves as the solution.&lt;/p&gt;

&lt;p&gt;The app is embedded below, and this post describes how you use it. It also goes
into the nitty-gritty of how it was built and explains all the formulas.&lt;/p&gt;

&lt;p&gt;The app uses many new features introduced in &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;this
release&lt;/a&gt;, principally &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;action formulas&lt;/a&gt;,
but also &lt;a href=&quot;/blog/2023/08/11/new-buttons.html&quot;&gt;three new button types&lt;/a&gt; (specifically, clipboard copy
buttons, go back buttons and go forward buttons), as well as the new &lt;a href=&quot;/blog/2023/08/11/let-function.html&quot;&gt;LET
function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’re encouraged to view the app and its formulas as you read along. It’s
available as a template when you create a new app under the &lt;em&gt;Sample: Tag editor&lt;/em&gt;
name.&lt;/p&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;p&gt;Here’s the app:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 665px; width: 100%; max-width: 540px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=sk9bb7&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;You can go straight to the tag editor by pressing &lt;strong&gt;I want to create new tags&lt;/strong&gt;.
Here’s what it looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-tag-editor/edit-new-tags.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-tag-editor/edit-new-tags.png&quot; alt=&quot;Editing new tags in the Tag editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type tags into the text fields, and be sure to heed the warnings about tags
being too long. (The maximum tag length is set to 30 characters.) Press the plus
and minus buttons to edit more or fewer tags, respectively.&lt;/p&gt;

&lt;p&gt;When you’re satisfied, press the &lt;strong&gt;Copy to clipboard&lt;/strong&gt; button to copy the tags,
separated by commas, to the clipboard. That enables them to be easily pasted
into the online marketplace.&lt;/p&gt;

&lt;p&gt;If you want to edit existing comma-separated tags, press the &lt;strong&gt;I want to
edit existing tags&lt;/strong&gt; button. Here’s what that screen looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-tag-editor/import-tags.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-tag-editor/import-tags.png&quot; alt=&quot;Importing tags into the Tag editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To edit those tags, press the &lt;strong&gt;Let’s go!&lt;/strong&gt; button. You’re then taken to the tag
editor, this time with the tags already filled out:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-tag-editor/edit-existing-tags.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-tag-editor/edit-existing-tags.png&quot; alt=&quot;Editing existing tags in the Tag editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll find that the tag editor looks slightly different. There are new fields
that list the original tags that you entered in the preceding step. Those are
not editable.&lt;/p&gt;

&lt;p&gt;The editable fields are just below the others, and initially contain the tags
from the preceding step. You’re welcome to edit those tags, though. This is a
good way to tweak your tags, and compare the tweaked tags to the original tags
you entered.&lt;/p&gt;

&lt;h2 id=&quot;under-the-hood&quot;&gt;Under the hood&lt;/h2&gt;

&lt;h3 id=&quot;the-welcome-screen&quot;&gt;The welcome screen&lt;/h3&gt;

&lt;p&gt;The welcome screen has two buttons that move the user to another screen. The
first button takes the user to the screen named &lt;em&gt;PasteTagsScreen&lt;/em&gt;, while the
second button takes the user to the screen named &lt;em&gt;EditTagsScreen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For reasons that will become clear later on, we need to keep track of which
button the user presses, so we can refer back to it later. To do that, we need
the buttons to be formula buttons, so they can run &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;action
formulas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These action formulas do two things: First, they record the decision the user
makes. Then, they take the user to a screen corresponding to their choice.&lt;/p&gt;

&lt;p&gt;To record the decision the user makes, we’ll add a new &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden text
field&lt;/a&gt; named &lt;em&gt;Choice&lt;/em&gt;. The first button, that enables the user to
edit existing tags, assigns the text string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;existing&lt;/code&gt; to &lt;em&gt;Choice&lt;/em&gt;, while the
second button, which enables the user to create new tags, assigns the text
string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the formula associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt;
property of the first button:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;existing&quot;; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(PasteTagsScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;existing&quot;;; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(PasteTagsScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt; assigns the appropriate value to &lt;em&gt;Choice&lt;/em&gt;. Then, the
&lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt; action function is used to bring the user forward to
&lt;em&gt;PasteTagsScreen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is the formula associated with the &lt;em&gt;OnPress&lt;/em&gt; property of the second button:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;new&quot;; &lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(App); &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditTagsScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;new&quot;;; &lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(App);; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditTagsScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Again, &lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt; assigns the appropriate value to &lt;em&gt;Choice&lt;/em&gt;. Before we
change the active screen to &lt;em&gt;EditTagsScreen&lt;/em&gt; with &lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;, we
also make sure that all the fields of the entire app are reset using the
&lt;span class=&quot;link function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt; action function.&lt;/p&gt;

&lt;p&gt;As we only want users to be able to move to other screens through the two
buttons, the &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt; property of the
welcome screen must be toggled to its “off” setting in the inspector.&lt;/p&gt;

&lt;p&gt;To select the screen, click anywhere in the blue area at the top of the app.
Then, click the toggle next to &lt;strong&gt;Next screen available&lt;/strong&gt; in the inspector. Both
areas are marked in this image:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-tag-editor/creator.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-tag-editor/creator.png&quot; alt=&quot;The property to toggle in the inspector&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-paste-screen&quot;&gt;The paste screen&lt;/h3&gt;

&lt;p&gt;If the user presses the &lt;strong&gt;I want to edit existing tags&lt;/strong&gt; button, they are taken
to the screen named &lt;em&gt;PasteTagsScreen&lt;/em&gt;. Once there, they can paste tags from
their online marketplace.&lt;/p&gt;

&lt;p&gt;The screen is simple, with a text field named &lt;em&gt;Tags&lt;/em&gt; and a button labeled
    &lt;strong&gt;Let’s go!&lt;/strong&gt; This button reads the entered tags, populates the screen enabling
users to edit tags — &lt;em&gt;EditTagsScreen&lt;/em&gt; — and finally moves the user forward
to just that screen.&lt;/p&gt;

&lt;p&gt;The button is a formula button, and runs an action formula that does what is
described above. Here’s the formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(SplitArray, &lt;span class=&quot;function&quot; name=&quot;TRIM&quot;&gt;TRIM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(Tags, &quot;,&quot;)), Tag1, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1, &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray, 1), &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()), Tag2, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 2, &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray, 2), &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()), Tag3, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 3, &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray, 3), &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()), EditTagsScreen!Original1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1; EditTagsScreen!Editable1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1; EditTagsScreen!Original2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag2; EditTagsScreen!Editable2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag2; EditTagsScreen!Original3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag3; EditTagsScreen!Editable3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag3; EditTagsScreen!TagCount &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(1, &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray))); &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditTagsScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(SplitArray; &lt;span class=&quot;function&quot; name=&quot;TRIM&quot;&gt;TRIM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(Tags; &quot;,&quot;)); Tag1; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray; 1); &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()); Tag2; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 2; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray; 2); &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()); Tag3; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 3; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray; 3); &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()); EditTagsScreen!Original1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1;; EditTagsScreen!Editable1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1;; EditTagsScreen!Original2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag2;; EditTagsScreen!Editable2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag2;; EditTagsScreen!Original3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag3;; EditTagsScreen!Editable3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag3;; EditTagsScreen!TagCount &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(1; &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray)));; &lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditTagsScreen)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(The app supports up to ten tags, but for reasons of brevity we’ll pretend that
it only supports three tags when reproducing its formulas. Refer to the sample
app in Calcapp Creator to see the full formulas.)&lt;/p&gt;

&lt;p&gt;The formula above uses the new &lt;span class=&quot;link function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt; function (which is covered
&lt;a href=&quot;/blog/2023/08/11/let-function.html&quot;&gt;by this blog post&lt;/a&gt;). It is used to assign names to values, which
can be used in later calculations in the same formula. The formula would have
included lots of repeated TEXTSPLIT invocations without LET, which would have
made it slower and harder to read.&lt;/p&gt;

&lt;p&gt;it assigns the name &lt;em&gt;SplitArray&lt;/em&gt; to an &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;array&lt;/a&gt; holding the tags
entered by the user. If you’re not familiar with arrays, you can think of them
as lists of values.&lt;/p&gt;

&lt;p&gt;If the &lt;em&gt;Tags&lt;/em&gt; text field contains the text string “First tag, Second tag,” the
goal is for &lt;em&gt;SplitArray&lt;/em&gt; to contain an array equivalent to this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &quot;First tag&quot;, &quot;Second tag&quot; }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &quot;First tag&quot;; &quot;Second tag&quot; }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To achieve this, we use the &lt;span class=&quot;link function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt; function, which splits
apart text strings and returns arrays of text strings, representing the
constituent parts of the original text string.&lt;/p&gt;

&lt;p&gt;This formula splits apart the value of the &lt;em&gt;Tags&lt;/em&gt; text field using a comma as a
delimiter:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(Tags, &quot;,&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(Tags; &quot;,&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In other words, all the text that is to the left of the first comma is placed
in the first element of the array, the text that is to the right of the first
comma, but to the left of the second comma, is placed in the second element,
etc.&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;TRIM&quot;&gt;TRIM&lt;/span&gt; function is invoked on the array returned from
TEXTSPLIT, so that space characters that appear before and after the actual tags
are removed.&lt;/p&gt;

&lt;p&gt;After assigning a value to &lt;em&gt;SplitArray&lt;/em&gt;, the formula assigns values to &lt;em&gt;Tag1&lt;/em&gt;,
&lt;em&gt;Tag2&lt;/em&gt; and &lt;em&gt;Tag3&lt;/em&gt;. Here’s the formula fragment used for &lt;em&gt;Tag1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1, &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray, 1), &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray) &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(SplitArray; 1); &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt; function returns the number of elements in an array. In
this context, it returns the number of tags entered by the user in the &lt;em&gt;Tags&lt;/em&gt;
text field. &lt;em&gt;Tag1&lt;/em&gt; is assigned the first element of &lt;em&gt;SplitArray&lt;/em&gt; if there is at
least one element in it, otherwise it is given a &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank value&lt;/span&gt;. &lt;em&gt;Tag2&lt;/em&gt; and &lt;em&gt;Tag3&lt;/em&gt; are similar.&lt;/p&gt;

&lt;p&gt;Finally, once &lt;em&gt;Tag1&lt;/em&gt;, &lt;em&gt;Tag2&lt;/em&gt; and &lt;em&gt;Tag3&lt;/em&gt; have been given their values, it’s time
to use these values to populate the next screen, &lt;em&gt;EditTagsScreen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The next screen has text fields where tags are entered. For reasons that will
become clear in the next section, there are two text fields per tag. For the
first tag, these are &lt;em&gt;Original1&lt;/em&gt; and &lt;em&gt;Editable1&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The next order of business is to assign values to both &lt;em&gt;Original1&lt;/em&gt; and
&lt;em&gt;Editable1&lt;/em&gt;, where both values are equal to the &lt;em&gt;Tag1&lt;/em&gt; value we have created:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;EditTagsScreen!Original1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1; EditTagsScreen!Editable1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;EditTagsScreen!Original1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1;; EditTagsScreen!Editable1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; Tag1;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Again, the second and third tags are handled similarly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;EditTagsScreen&lt;/em&gt; has another field we need to concern ourselves with. &lt;em&gt;TagCount&lt;/em&gt;
contains the number of visible tags. (Users can press &lt;a href=&quot;/blog/2018/01/10/steppers.html&quot;&gt;buttons&lt;/a&gt; to
make more or fewer tags appear.)&lt;/p&gt;

&lt;p&gt;If the user has entered three tags in the &lt;em&gt;Tags&lt;/em&gt; text field, we want three tags
to be visible. To do so, we use this formula fragment:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;EditTagsScreen!TagCount &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(1, &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;EditTagsScreen!TagCount &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(1; &lt;span class=&quot;function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt;(SplitArray))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SplitArray&lt;/em&gt; contains the tags entered by the user as an array, and the
&lt;span class=&quot;link function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt; function is used to return the number of tags.&lt;/p&gt;

&lt;p&gt;We wrap the return value from SIZE using the &lt;span class=&quot;link function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt; function to
ensure that the lowest number that is returned is 1. The reason is that even if
users don’t enter anything in the &lt;em&gt;Tags&lt;/em&gt; field, we still want a single tag to be
editable on the next screen.&lt;/p&gt;

&lt;p&gt;Finally, we use the &lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt; function to move the user forward
to &lt;em&gt;EditTagsScreen&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditTagsScreen)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;GOFORWARD&quot;&gt;GOFORWARD&lt;/span&gt;(EditTagsScreen)&lt;/span&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-edit-tags-screen&quot;&gt;The edit tags screen&lt;/h3&gt;

&lt;p&gt;The edit tags screen consists of three text fields per tag, which are all part
of a single form group. The first tag consists of the text fields &lt;em&gt;Original1&lt;/em&gt;,
&lt;em&gt;Editable1&lt;/em&gt; and &lt;em&gt;CharactersLeft1&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When users reach &lt;em&gt;EditTagsScreen&lt;/em&gt; through &lt;em&gt;PasteTagsScreen&lt;/em&gt;, all text fields are
visible. The first tag read from the &lt;em&gt;Tags&lt;/em&gt; text field of &lt;em&gt;PasteTagsScreen&lt;/em&gt; is
assigned to both the &lt;em&gt;Original1&lt;/em&gt; and &lt;em&gt;Editable1&lt;/em&gt; text fields.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Original1&lt;/em&gt; text field is always &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Enabled&quot;&gt;disabled&lt;/span&gt;, so
that users can compare the tag they are changing to the original. The
&lt;em&gt;Editable1&lt;/em&gt; text field is the one that users modify.&lt;/p&gt;

&lt;p&gt;When users reach &lt;em&gt;EditTagsScreen&lt;/em&gt; directly from the welcome screen, though, the
&lt;em&gt;Original1&lt;/em&gt; field is not visible. To achieve this, we make use of the fact that
we have noted which button the user pressed, by storing either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;existing&lt;/code&gt; or
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt; in the &lt;em&gt;Choice&lt;/em&gt; hidden field of the welcome screen.&lt;/p&gt;

&lt;p&gt;This formula is associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property
of &lt;em&gt;Original1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;WelcomeScreen!Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;existing&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;WelcomeScreen!Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;existing&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;That means that when users reach this screen directly from the welcome screen,
&lt;em&gt;Editable1&lt;/em&gt; is visible, but &lt;em&gt;Original1&lt;/em&gt; is not. The default label of &lt;em&gt;Editable1&lt;/em&gt;
is “Editable”, and we’d like it to simply read “Tag” if &lt;em&gt;Original1&lt;/em&gt; is not
visible.&lt;/p&gt;

&lt;p&gt;To achieve this, we associate this formula with the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;
property of &lt;em&gt;Editable1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(WelcomeScreen!Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;existing&quot;, &quot;Editable&quot;, &quot;Tag&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(WelcomeScreen!Choice &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;existing&quot;; &quot;Editable&quot;; &quot;Tag&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;CharactersLeft1&lt;/em&gt; field holds the number of characters that the user may add
to the tag without running afoul of the length limits. Here’s its formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;MaxCharacters &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;LEN&quot;&gt;LEN&lt;/span&gt;(Editable1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;MaxCharacters &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;LEN&quot;&gt;LEN&lt;/span&gt;(Editable1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;MaxCharacters&lt;/em&gt; &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden number field&lt;/a&gt; holds the value 30.
(Feel free to change it to anything you like to suit the online marketplace
you’re using, or better yet, enable the user to edit it directly.) The
&lt;span class=&quot;link function&quot; name=&quot;LEN&quot;&gt;LEN&lt;/span&gt; function calculates the length of a text string.&lt;/p&gt;

&lt;p&gt;To be extra clear, we modify the label of the form group to hold the same
information, along with a warning triangle if there are too many characters in
the tag.&lt;/p&gt;

&lt;p&gt;Here’s the formula of the &lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt; property of
&lt;em&gt;Tag1FormGroup&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(CharactersLeft, MaxCharacters &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;LEN&quot;&gt;LEN&lt;/span&gt;(Editable1), &quot;Tag 1 — &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; CharactersLeft &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; characters left&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CharactersLeft &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 0, &quot; ⚠️&quot;))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(CharactersLeft; MaxCharacters &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;LEN&quot;&gt;LEN&lt;/span&gt;(Editable1); &quot;Tag 1 — &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; CharactersLeft &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; characters left&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CharactersLeft &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 0; &quot; ⚠️&quot;))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;It uses the &lt;span class=&quot;link function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt; function to assign a name to the number of
remaining characters. It would have been easier to simply refer to the
&lt;em&gt;CharactersLeft1&lt;/em&gt; field, but this way, we can remove those redundant fields in
the future, without having to change any other formulas.&lt;/p&gt;

&lt;p&gt;The actual label is calculated using &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt;, which is used to join
text strings together. A warning triangle is only added if the number of
remaining characters is a negative number.&lt;/p&gt;

&lt;p&gt;The final bit of business we need to attend to for the first tag is whether it
should be visible. There is a field, &lt;em&gt;TagCount&lt;/em&gt;, which holds the number of tags
to show to the user. There is a &lt;a href=&quot;/blog/2018/01/10/steppers.html&quot;&gt;stepper&lt;/a&gt; associated with that field,
enabling users to show more or fewer fields.&lt;/p&gt;

&lt;p&gt;To make it work, we associate the following formula with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property of &lt;em&gt;Tag1FormGroup&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;TagCount &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;TagCount &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 1&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(Technically, the first tag is always visible, because a number lower than 1 is
never assigned to &lt;em&gt;TagCount&lt;/em&gt;. This formula mostly exists for consistency with
the other tags.)&lt;/p&gt;

&lt;p&gt;That’s it for the first tag! The fields and formulas that realize the other two
tags are similar. Refer to the sample app in Calcapp Creator to see how it all
comes together.&lt;/p&gt;

&lt;p&gt;We’re nearly done! There is a text field, &lt;em&gt;Tags&lt;/em&gt;, that brings all tags together,
as a comma-separated text string. Here’s its formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(TagArray, &lt;span class=&quot;function&quot; name=&quot;TRIM&quot;&gt;TRIM&lt;/span&gt;({ Editable1, Editable2, Editable3 }), &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;, TRUE, TagArray))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt;(TagArray; &lt;span class=&quot;function&quot; name=&quot;TRIM&quot;&gt;TRIM&lt;/span&gt;({ Editable1; Editable2; Editable3 }); &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;; TRUE; TagArray))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Again, we use &lt;span class=&quot;link function&quot; name=&quot;LET&quot;&gt;LET&lt;/span&gt; to assign names to make the formula easier to
read. First, we collect the tags edited by the user as an array. We apply the
&lt;span class=&quot;link function&quot; name=&quot;TRIM&quot;&gt;TRIM&lt;/span&gt; function to this array, to ensure that no space characters
appear before or after the tags. Finally, we use &lt;span class=&quot;link function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt; to
create a single text string from the array elements, effectively creating a
comma-separated text string containing all the tags.&lt;/p&gt;

&lt;p&gt;That’s the text string that users should copy to the clipboard, to paste
directly into the online marketplace they use.&lt;/p&gt;

&lt;p&gt;To make it easy to copy the text string to the clipboard, a
clipboard copy button appears directly underneath the text field,
whose &lt;span class=&quot;link property&quot; parent-type=&quot;ClipboardCopyButton&quot; name=&quot;CopiedText&quot;&gt;CopiedText&lt;/span&gt; property is
set to &lt;span class=&quot;formula decimalpoint&quot;&gt;Tags&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Tags&lt;/span&gt;, referencing the text field.&lt;/p&gt;

&lt;p&gt;The last item that appears on this screen is a button that allows the user to go
back to the previous screen. It also removes the tags entered on
&lt;em&gt;PasteTagsScreen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To achieve this, the button is a formula button, and the following action
formula is associated with its &lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;PasteTagsScreen!Tags &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;&quot;; &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;()&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;PasteTagsScreen!Tags &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &quot;&quot;;; &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;()&lt;/span&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 07:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/tag-editor.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/tag-editor.html</guid>
        
        <category>Sample app</category>
        
        
      </item>
    
      <item>
        <title>Feature: More ways to access our documentation</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our documentation is now integrated into Calcapp Creator. A popup now appears
  with function parameter information when editing formulas. Documentation is
  also part of autocomplete.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;In 2021, we &lt;a href=&quot;/blog/2021/11/12/documentation.html&quot;&gt;dramatically improved our documentation&lt;/a&gt;. We added
thousands of formula examples and wrote enough text to rival The Lord of the
Rings trilogy.&lt;/p&gt;

&lt;p&gt;The only problem was that the documentation wasn’t very accessible. It wasn’t
built into Calcapp Creator in any meaningful way, so you had to go to our
separate documentation site to read it. It was easy to forget that it was there,
and feel bewildered when a formula error popped up, not knowing where to turn.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;Today&lt;/a&gt;, we are taking steps to integrate the documentation
much more closely with the app designer.&lt;/p&gt;

&lt;h2 id=&quot;function-parameter-popup&quot;&gt;Function parameter popup&lt;/h2&gt;

&lt;p&gt;When you write formulas, and specifically when you’re editing a parameter to
a function, a helpful popup will appear to let you know what parameter you’re
editing and what it does:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-documentation/parameter-popup.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-documentation/parameter-popup.png&quot; alt=&quot;The popup that appears when you&apos;re editing a function parameter&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The popup displays the name of the function you’re editing, with the current
parameter highlighted in purple. (&lt;strong&gt;?&lt;/strong&gt; is displayed after optional parameters
and &lt;strong&gt;…&lt;/strong&gt; is displayed if you can pass multiple parameters.)&lt;/p&gt;

&lt;p&gt;Below the first line is the first sentence of the documentation for the
parameter. Press &lt;strong&gt;More »&lt;/strong&gt; to be brought directly to the full documentation.&lt;/p&gt;

&lt;p&gt;If you find that the parameter popup is getting in the way, close it using the
&lt;strong&gt;✕&lt;/strong&gt; button. If you want it to reappear, switch to a different item in the app
designer and then back to the original item.&lt;/p&gt;

&lt;h2 id=&quot;autocomplete-integration&quot;&gt;Autocomplete integration&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/autocomplete.html&quot;&gt;Autocomplete&lt;/a&gt; enables you to quickly find the function or
property you’re looking for when editing formulas (among other things).
Our documentation has now been integrated into autocomplete, appearing
when you select a function or a property.&lt;/p&gt;

&lt;p&gt;Here, the &lt;span class=&quot;link function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt; function is selected, and the first sentence
from its documentation appears to the left:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-documentation/autocomplete-function.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-documentation/autocomplete-function.png&quot; alt=&quot;Function documentation appearing in the autocomplete popup&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like with the parameter popup, you can access the full documentation by pressing
&lt;strong&gt;More »&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When autocomplete shows properties, the first sentence from the documentation is
also displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-documentation/autocomplete-property.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-documentation/autocomplete-property.png&quot; alt=&quot;Property documentation appearing in the autocomplete popup&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;formula-examples&quot;&gt;Formula examples&lt;/h2&gt;

&lt;p&gt;When the formula field isn’t displaying a formula, it now displays a formula
example:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-documentation/formula-example-value.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-documentation/formula-example-value.png&quot; alt=&quot;A formula example for the Value property&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The formula examples are specific to a certain property. Here’s a formula
example for the &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt; property of a number field:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-documentation/formula-example-valid.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-documentation/formula-example-valid.png&quot; alt=&quot;A formula example for the Valid property&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some properties, like the &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; property of number
fields, have multiple formula examples. The example shown is chosen at random.&lt;/p&gt;

&lt;h2 id=&quot;other-ways-to-access-our-documentation&quot;&gt;Other ways to access our documentation&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;fx&lt;/strong&gt; symbol, which appears to the left of the formula field, is now a
button that may be pressed to access the documentation for the current property.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-documentation/other.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-documentation/other.png&quot; alt=&quot;Other ways to access documentation&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also press the &lt;strong&gt;Property help&lt;/strong&gt; link in the inspector to access the
property documentation for the type of item you’re viewing.&lt;/p&gt;

&lt;h2 id=&quot;categorized-properties&quot;&gt;Categorized properties&lt;/h2&gt;

&lt;p&gt;Finally, the properties in the left-hand sidebar of our documentation website
have now been categorized:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-better-documentation/categories.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-better-documentation/categories.png&quot; alt=&quot;Properties have been categorized&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, only colors and various &lt;a href=&quot;/blog/2023/08/11/items.html&quot;&gt;Items properties&lt;/a&gt; appear in their own
categories. We think it makes the list of properties less cluttered, especially
for things like &lt;a href=&quot;/learn/properties/formScreen/&quot;&gt;form screens&lt;/a&gt;, which have many properties.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 06:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/better-documentation.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/better-documentation.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Tip: Ask users questions with action formulas</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Use action formulas to ask users a series of questions. The answers
  are then fed into action functions that act on the information given.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;Action formulas&lt;/a&gt; can be used for a variety of things,
including sending messages if a field is valid and displaying an alert box
if it isn’t, as well as &lt;a href=&quot;/blog/2023/08/11/calculation-buttons.html&quot;&gt;performing calculations only when a button is
pressed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This tip focuses on asking users questions, using message boxes. What makes this
possible are the new &lt;a href=&quot;/learn/formulas/section-action.html&quot;&gt;action functions&lt;/a&gt; &lt;span class=&quot;link function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;
and &lt;span class=&quot;link function&quot; name=&quot;PROMPT.NUMBER&quot;&gt;PROMPT.NUMBER&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Both action functions are used to ask users for information. PROMPT reads text
strings, whereas PROMPT.NUMBER only reads numbers. &lt;span class=&quot;link function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt; is used
to read the entered values.&lt;/p&gt;

&lt;p&gt;This formula asks the user to enter the email address where a report should be
sent, before sending the report:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Enter email address:&quot;), &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, Result))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Enter email address:&quot;); &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; Result))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The second parameter to AWAIT has access to a special value named
&lt;code&gt;Result&lt;/code&gt;, containing the result communicated by the action. For
&lt;span class=&quot;link function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt; the result is the text string entered by the user.
For &lt;span class=&quot;link function&quot; name=&quot;PROMPT.NUMBER&quot;&gt;PROMPT.NUMBER&lt;/span&gt;, the result is the number entered by
the user.&lt;/p&gt;

&lt;p&gt;(This is similar to the third parameter to AWAIT, which has access to a special
value named &lt;code&gt;Error&lt;/code&gt;, with additional information on what went wrong.)&lt;/p&gt;

&lt;p&gt;If you like, you can use &lt;code&gt;-&amp;gt;&lt;/code&gt; to rename the &lt;code&gt;Result&lt;/code&gt; value:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Enter email address:&quot;), EmailAddress -&amp;gt; &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }, EmailAddress))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Enter email address:&quot;); EmailAddress -&amp;gt; &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;({ App }; EmailAddress))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;You can ask the user any number of questions:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;First value:&quot;), Value1 -&amp;gt; &lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Second value:&quot;), Value2 -&amp;gt; &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;First value: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Value1 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, second value: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Value2 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;First value:&quot;); Value1 -&amp;gt; &lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;(&quot;Second value:&quot;); Value2 -&amp;gt; &lt;span class=&quot;function&quot; name=&quot;ALERT&quot;&gt;ALERT&lt;/span&gt;(&quot;First value: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Value1 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, second value: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Value2 &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;When asking multiple questions with &lt;span class=&quot;link function&quot; name=&quot;PROMPT&quot;&gt;PROMPT&lt;/span&gt;, it is necessary to
rename the &lt;code&gt;Result&lt;/code&gt; value. If we don’t, there is no way to access results
other than the last one.&lt;/p&gt;

&lt;p&gt;Finally, use &lt;span class=&quot;link function&quot; name=&quot;CONFIRM&quot;&gt;CONFIRM&lt;/span&gt; to ask users to confirm a choice. This
formula asks the user to confirm before resetting all fields of the app,
immediately followed by displaying the first screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;CONFIRM&quot;&gt;CONFIRM&lt;/span&gt;(&quot;Start over?&quot;), &lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(App); &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;(FirstScreen))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;CONFIRM&quot;&gt;CONFIRM&lt;/span&gt;(&quot;Start over?&quot;); &lt;span class=&quot;function&quot; name=&quot;RESET&quot;&gt;RESET&lt;/span&gt;(App);; &lt;span class=&quot;function&quot; name=&quot;GOBACK&quot;&gt;GOBACK&lt;/span&gt;(FirstScreen))&lt;/span&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 05:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/asking-questions.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/asking-questions.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Perform calculations when a button is pressed</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Use a formula button to calculate results when a button is pressed instead of
  while the user is typing.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Perform%20calculations%20when%20a%20button%20is%20pressed
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Apps normally perform calculations while the user is typing. Sometimes, though,
you don’t want to distract users while they enter data, and only show the
results once a button is pressed. &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;Our new release&lt;/a&gt; makes
this possible.&lt;/p&gt;

&lt;p&gt;Here’s the &lt;a href=&quot;/blog/2019/08/10/bmi.html&quot;&gt;Body Mass Index (BMI) sample app&lt;/a&gt;, modified to use a
calculation button instead of calculating results right away:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 665px; width: 100%; max-width: 540px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=rhtm3r&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;Formula buttons are the tool of choice because they run so-called
&lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;action formulas&lt;/a&gt;. These formulas can do things like
&lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;send reports&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;CLIPBOARDCOPY&quot;&gt;copy values to the clipboard&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;show a different screen&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Crucially, they can also assign values to fields, using the new
&lt;span class=&quot;link binaryOperator&quot; name=&quot;:=&quot;&gt;:=&lt;/span&gt; operator. The new operator makes it easy to add calculation
buttons, simply by associating formulas that use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; operator with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt; properties of formula buttons.&lt;/p&gt;

&lt;p&gt;The modified BMI sample app above has removed the formula from the
&lt;em&gt;CalculatedBmi&lt;/em&gt; hidden field. Instead, its new calculation button uses this
action formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; WeightInKg &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; HeightInM&lt;span class=&quot;binaryOperator&quot; name=&quot;EXPONENTIATION&quot;&gt;^&lt;/span&gt;2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; WeightInKg &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; HeightInM&lt;span class=&quot;binaryOperator&quot; name=&quot;EXPONENTIATION&quot;&gt;^&lt;/span&gt;2&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The calculation to the right of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; operator is the exact same formula that
was previously associated with the &lt;em&gt;CalculatedBmi&lt;/em&gt; hidden field.&lt;/p&gt;

&lt;p&gt;This is the only modification you need to make to the BMI sample app to make it
calculate its results using a button. There are still other hidden fields —
&lt;em&gt;Category&lt;/em&gt; and &lt;em&gt;BmiRatio&lt;/em&gt; — that are not calculated explicitly by the new
button. Instead, these fields rely on the &lt;em&gt;CalculatedBmi&lt;/em&gt; field, and are updated
when the button assigns a new value to it.&lt;/p&gt;

&lt;p&gt;A calculation button can calculate several results, by separating calculations
with &lt;span class=&quot;formula decimalpoint&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;;;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;This action formula explicitly assigns values not only to the &lt;em&gt;CalculatedBmi&lt;/em&gt;
field, but also to the &lt;em&gt;Category&lt;/em&gt; and &lt;em&gt;BmiRatio&lt;/em&gt; fields:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; WeightInKg &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; HeightInM&lt;span class=&quot;binaryOperator&quot; name=&quot;EXPONENTIATION&quot;&gt;^&lt;/span&gt;2; Category &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 18.5, &quot;underweight&quot;, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 25, &quot;normal&quot;, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 30, &quot;overweight&quot;, &quot;obese&quot;))); BmiRatio &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;MIN&quot;&gt;MIN&lt;/span&gt;(30, &lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(18.5, CalculatedBmi)) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; 18.5) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; (30 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; 18.5)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; WeightInKg &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; HeightInM&lt;span class=&quot;binaryOperator&quot; name=&quot;EXPONENTIATION&quot;&gt;^&lt;/span&gt;2;; Category &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 18,5; &quot;underweight&quot;; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 25; &quot;normal&quot;; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(CalculatedBmi &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 30; &quot;overweight&quot;; &quot;obese&quot;)));; BmiRatio &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; (&lt;span class=&quot;function&quot; name=&quot;MIN&quot;&gt;MIN&lt;/span&gt;(30; &lt;span class=&quot;function&quot; name=&quot;MAX&quot;&gt;MAX&lt;/span&gt;(18,5; CalculatedBmi)) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; 18,5) &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; (30 &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; 18,5)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Consider &lt;a href=&quot;/blog/2023/08/11/grab-bag.html#insert-line-breaks-in-formulas&quot;&gt;adding line breaks&lt;/a&gt; to formulas like the one
above to make it easier to read, just after &lt;span class=&quot;formula decimalpoint&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;;;&lt;/span&gt;. To
insert a line break, press &lt;kbd&gt;Alt&lt;/kbd&gt;+&lt;kbd&gt;Enter&lt;/kbd&gt;.&lt;/p&gt;

&lt;p&gt;For details on how the calculations work, refer to the &lt;a href=&quot;/blog/2019/08/10/bmi.html&quot;&gt;blog post we
wrote&lt;/a&gt; when announcing the BMI sample app.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 04:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/calculation-buttons.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/calculation-buttons.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Require a button to be pressed</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Prevent users from seeing certain information, or from moving on to the next
  screen, if a button has not been pressed. This can be achieved through a
  formula button and a hidden field.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Require%20a%20button%20to%20be%20pressed
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Sometimes, it is important for users to perform an action before they can
proceed. For instance, you may want to require a button to be pressed before
showing a calculated value.&lt;/p&gt;

&lt;p&gt;Here’s an example app that demonstrates what we’d like to accomplish (try
pressing the button):&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 665px; width: 100%; max-width: 540px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=yig60&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;As you can see, the extra information is only displayed once the button
has been pressed.&lt;/p&gt;

&lt;p&gt;With &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;our new release&lt;/a&gt;, you can achieve this
using &lt;a href=&quot;/blog/2023/08/11/action-formulas.html&quot;&gt;formula buttons&lt;/a&gt;. A formula button runs a
so-called action formula, which can take any action you like,
including &lt;span class=&quot;link function&quot; name=&quot;GOFORWARD&quot;&gt;changing the active screen&lt;/span&gt; or
&lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;sending an email back to the office with the collected information&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Of course, regular buttons can do all that too. What makes formula
buttons appealing here is that they can perform multiple actions,
including assigning values to fields.&lt;/p&gt;

&lt;p&gt;In order to keep track of whether the user has pressed the button,
we’ll add a &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden switch field&lt;/a&gt;, which we’ll name
&lt;em&gt;IsFormSubmitted&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Then, we’ll add a formula button, with the following formula associated
with its &lt;span class=&quot;link property&quot; parent-type=&quot;FormulaButton&quot; name=&quot;OnPress&quot;&gt;OnPress&lt;/span&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;IsFormSubmitted &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; TRUE; &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;(App, &quot;office@example.com&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;IsFormSubmitted &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; TRUE;; &lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;(App; &quot;office@example.com&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above does two things: it sets &lt;em&gt;IsFormSubmitted&lt;/em&gt; to TRUE,
and it sends a report through email, containing all fields of the app,
using the &lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt; function. That function can do
everything a regular email report button can, by setting the appropriate
parameters.&lt;/p&gt;

&lt;p&gt;Now that the &lt;em&gt;IsFormSubmitted&lt;/em&gt; field reflects whether the button has been
pressed, we can rely on its value from formulas.&lt;/p&gt;

&lt;p&gt;The example app above has the following formula associated with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormGroup&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property of the form group holding the
results:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;IsFormSubmitted&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;IsFormSubmitted&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The form group holding the contact form has the following formula associated
with its &lt;em&gt;Visible&lt;/em&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(IsFormSubmitted)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;NOT&quot;&gt;NOT&lt;/span&gt;(IsFormSubmitted)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above ensures that the contact form becomes invisible once the
button has been pressed.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;OnPress&lt;/em&gt; formula above has one potential problem: it immediately sets
&lt;em&gt;IsFormSubmitted&lt;/em&gt; to TRUE. That means that users get access to the results
even if the report is not sent successfully, which may not be what we want.&lt;/p&gt;

&lt;p&gt;Here’s another version which waits for the EMAILREPORT function to notify us
that the report has been sent successfully:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;(App, &quot;office@example.com&quot;), IsFormSubmitted &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; TRUE)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AWAIT&quot;&gt;AWAIT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt;(App; &quot;office@example.com&quot;); IsFormSubmitted &lt;span class=&quot;binaryOperator&quot; name=&quot;ASSIGNMENT&quot;&gt;:=&lt;/span&gt; TRUE)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(Note that even if a report is sent successfully, that does not mean that it
will necessarily arrive at its destination, due to factors outside the control
of your app.)&lt;/p&gt;

&lt;p&gt;If you instead want to prevent users from moving on to the next screen
until the button has been pressed, associate this formula with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt; property of the screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;IsFormSubmitted&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;IsFormSubmitted&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To learn more about how this property is set, &lt;a href=&quot;/blog/2023/08/11/tag-editor.html#the-welcome-screen&quot;&gt;refer to the blog post describing
our new sample app&lt;/a&gt;, which has detailed instructions.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 03:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/required-button.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/required-button.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Feature: Easily determine what fields to reset or include in a report</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  The fields to reset and the fields to include in a report can now be set
  directly in the inspector, without using a formula.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Prior to our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;last big release&lt;/a&gt;, determining
what fields to include in a report or what fields to reset was difficult
or impossible. That’s why we introduced the new &lt;em&gt;IncludedFields&lt;/em&gt; property of
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;email report buttons&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;IncludedFields&quot;&gt;open report buttons&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;ServerRelayButton&quot; name=&quot;IncludedFields&quot;&gt;server relay buttons&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;ResetButton&quot; name=&quot;IncludedFields&quot;&gt;reset buttons&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;(Refer to our blog posts from 2021 for all the details, covering
&lt;a href=&quot;/blog/2021/11/12/reports.html&quot;&gt;reports&lt;/a&gt; and &lt;a href=&quot;/blog/2021/11/12/reset-buttons.html&quot;&gt;reset buttons&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;The only downside was that you had to use formulas to determine what fields to
include. That approach is powerful, because it enables you to determine what
fields to include based on information entered in the app and calculated by the
app.&lt;/p&gt;

&lt;p&gt;Typically, though, what fields to include does not change. Requiring you to use
formulas for something as basic as selecting what fields to use arguably isn’t
particularly user-friendly, especially for apps that contain few other formulas.&lt;/p&gt;

&lt;p&gt;For that reason, &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;our new release&lt;/a&gt; introduces a field
picker.&lt;/p&gt;

&lt;p&gt;To determine what fields to reset using a field picker, select &lt;strong&gt;Reset specific
fields&lt;/strong&gt; from the drop-down in the inspector when a reset field is selected:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-inspector-fields/reset-button-menu.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-inspector-fields/reset-button-menu.png&quot; alt=&quot;Selecting to reset specific fields&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields to reset&lt;/strong&gt; appears in the inspector, along with a button for selecting
the fields:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-inspector-fields/reset-button-marked-pen.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-inspector-fields/reset-button-marked-pen.png&quot; alt=&quot;The pen button that allows you to select what fields to reset&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the pen button, and this field picker appears:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-inspector-fields/field-picker.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-inspector-fields/field-picker.png&quot; alt=&quot;The field picker&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The left-hand side of the field picker contains all screens. Press a screen, and
the right-hand side of the field picker displays all fields of the selected
screen. Make sure that the fields you wish to reset all checked, and then press
&lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Press the &lt;i class=&quot;mdi mdi-check-all&quot;&gt;&lt;/i&gt; button in the upper-left corner to
check all fields and the &lt;i class=&quot;mdi mdi-checkbox-blank-off-outline&quot;&gt;&lt;/i&gt;
button to uncheck all fields.&lt;/p&gt;

&lt;p&gt;The order of the fields isn’t important when resetting fields, or when sending
them to &lt;a href=&quot;/blog/2018/05/18/zapier-video.html&quot;&gt;a third-party service like Zapier&lt;/a&gt; through a server relay
button. However, when fields are included in reports, the order matters.&lt;/p&gt;

&lt;p&gt;For that reason, the field picker has a second page where you decide what fields
to include in a report:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-inspector-fields/field-picker-order.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-inspector-fields/field-picker-order.png&quot; alt=&quot;Changing the field order using a field picker&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The grayed-out text on the right contains the name of the screen the field is
part of, as well as the name of its form group. If there is no grayed-out text,
the field is part of the same screen and form group as the field above it.&lt;/p&gt;

&lt;p&gt;Drag the &lt;i class=&quot;mdi mdi-view-headline&quot;&gt;&lt;/i&gt; handle to change the order of the
fields and press the &lt;i class=&quot;mdi mdi-refresh&quot;&gt;&lt;/i&gt; button to go back to the
original order. When you’re done, press &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 02:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/inspector-fields.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/inspector-fields.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Easily decide the next screen</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  The screen that follows other screens and navigators can now be set directly
  in the inspector, without using a formula.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;last big release&lt;/a&gt; made it possible to &lt;a href=&quot;/blog/2021/11/12/next-screen.html&quot;&gt;determine
what screen should follow another screen or navigator&lt;/a&gt; using a
formula.&lt;/p&gt;

&lt;p&gt;That feature has many uses, including being able to use &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; to
show a warning message instead of a regular form screen when the user attempts
to move forward if a value doesn’t check out. The feature can also be used to
make all list screen navigators go to the same screen.&lt;/p&gt;

&lt;p&gt;For full details, refer to the &lt;a href=&quot;/blog/2021/11/12/next-screen.html&quot;&gt;blog post we wrote in 2021&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While it’s often useful to associate a formula with the
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;NextScreen&lt;/span&gt; property, it
is very common for these formulas to simply state the name of
a screen. This is the case when all navigators of a list screen
lead to the same screen, for instance.&lt;/p&gt;

&lt;p&gt;That makes this feature needlessly hard to use, especially for users who are not
comfortable with formulas. (We have customers whose apps only collect data and
send it off using a report button. These apps often use no formulas at all.)&lt;/p&gt;

&lt;p&gt;For that reason, the inspector now lets you decide the next screen using a
drop-down:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-inspector-screen/next-screen.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-inspector-screen/next-screen.png&quot; alt=&quot;Selecting the next screen in the inspector&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, the regular next screen is displayed (reachable in Calcapp Creator
by pressing the &lt;i class=&quot;mdi mdi-arrow-right&quot;&gt;&lt;/i&gt; button in the top-right
corner of the app). If you press the drop-down, a menu containing all screens in
the app is displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-inspector-screen/next-screen-menu.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-inspector-screen/next-screen-menu.png&quot; alt=&quot;The next screen menu in the inspector&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also use the new screen selector for the &lt;em&gt;Target&lt;/em&gt; properties of
the new &lt;span class=&quot;link property&quot; parent-type=&quot;GoForwardButton&quot; name=&quot;Target&quot;&gt;go forward&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;GoBackButton&quot; name=&quot;Target&quot;&gt;go back&lt;/span&gt; buttons:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-08-11-inspector-screen/target-screen.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-08-11-inspector-screen/target-screen.png&quot; alt=&quot;The target screen property of a go forward button&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you already have formulas associated with the &lt;em&gt;NextScreen&lt;/em&gt; property that only
state the name of a screen, you can safely remove these formulas and select the
screen from the drop-down menu instead.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 01:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/inspector-screen.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/inspector-screen.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Named function parameters</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Function parameters can now be named, making formulas easier to read.
  Named parameters can also make formulas significantly shorter.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Some of Calcapp’s formula functions accept a large number of parameters, which
can make formulas hard to read. Our &lt;a href=&quot;/blog/2023/08/11/release.html&quot;&gt;new release&lt;/a&gt; includes
support for &lt;em&gt;named parameters&lt;/em&gt;, allowing you to precede a parameter value with
its name, followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; and a space.&lt;/p&gt;

&lt;p&gt;For instance, these two formulas are now equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(23, 2, 2, FALSE, 1, FALSE, &quot;$&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(23; 2; 2; FALSE; 1; FALSE; &quot;$&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(Number: 23, MinimumNumberOfDecimalPlaces: 2, MaximumNumberOfDecimalPlaces: 2, OmitThousandsSeparators: FALSE, MinimumNumberOfIntegerDigits: 1, UseAccountingStyle: FALSE, LeadingUnit: &quot;$&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(Number: 23; MinimumNumberOfDecimalPlaces: 2; MaximumNumberOfDecimalPlaces: 2; OmitThousandsSeparators: FALSE; MinimumNumberOfIntegerDigits: 1; UseAccountingStyle: FALSE; LeadingUnit: &quot;$&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;All parameters don’t need to be named, but once a parameter has been named, the
remaining parameters must also be named.&lt;/p&gt;

&lt;p&gt;Named parameters make it possible to provide parameters out-of-order and to omit
optional parameters that normally would have been expected to precede a
parameter, had it not been named. Omitted optional parameters use default
values.&lt;/p&gt;

&lt;p&gt;The formula above happens to use default values for all parameters other than
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Number&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LeadingUnit&lt;/code&gt;. As such, those optional parameters can be removed
from the formula.&lt;/p&gt;

&lt;p&gt;To put that into practice, consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(23, LeadingUnit: &quot;$&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(23; LeadingUnit: &quot;$&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The delightfully-short formula above is fully equivalent to the first two
formulas.&lt;/p&gt;

&lt;p&gt;We suggest that you use named parameters when they help make a formula easier to
read.&lt;/p&gt;

&lt;p&gt;We added named parameters to Calcapp to make existing functions like
&lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt; easier to use, but also in consideration of new
functions like &lt;span class=&quot;link function&quot; name=&quot;EMAILREPORT&quot;&gt;EMAILREPORT&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;OPENREPORT&quot;&gt;OPENREPORT&lt;/span&gt;.
Those functions support a very large number of optional parameters, and named
parameters enable you to only provide the parameters you care about, omitting
the rest.&lt;/p&gt;

&lt;p&gt;To learn the names of the parameters to formula functions, use our &lt;a href=&quot;/learn/formulas/&quot;&gt;formula
documentation&lt;/a&gt;. Also, all parameter names are part of our
new &lt;a href=&quot;/blog/2023/08/11/autocomplete.html&quot;&gt;autocomplete&lt;/a&gt; feature, making them easy to insert.&lt;/p&gt;

&lt;h2 id=&quot;colons-in-ranges-versus-colons-used-for-named-parameters&quot;&gt;Colons in ranges versus colons used for named parameters&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; is also used in formulas to create &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;ranges&lt;/a&gt;, like
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field4&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field4&lt;/span&gt;, which often expands to
&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field2, Field3, Field4 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field2; Field3; Field4 }&lt;/span&gt;. Previously,
you could write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; with space either to the left or to the right.
Now, however, Calcapp will interpret &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; with a space to the right
as an attempt to name a parameter.&lt;/p&gt;

&lt;p&gt;As part of our &lt;a href=&quot;/blog/2021/11/12/large-apps.html&quot;&gt;automatic migration process&lt;/a&gt;, we have
changed all formulas with ambiguous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt; characters, so that they
are always interpreted as being part of ranges.&lt;/p&gt;

</description>
        <pubDate>Fri, 11 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/08/11/named-parameters.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/08/11/named-parameters.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Our next release and upcoming subscription changes</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our new release is our biggest yet. In this blog post, we explain why it&apos;s
  taken longer than anticipated, and detail some upcoming changes to your
  subscription.
&lt;/div&gt;

&lt;p&gt;Back in September, we announced &lt;a href=&quot;/blog/2022/09/11/update.html&quot;&gt;major new features&lt;/a&gt; for our
next release. However, in December, we shared that we had &lt;a href=&quot;/blog/2022/12/21/delay.html&quot;&gt;delayed the
release&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that it’s June, we owe you an update, and an explanation for the delay.&lt;/p&gt;

&lt;p&gt;The good news is that the release is coming along well, and that it will be our
biggest one yet. The delay was not due to development issues, but because we
have been adding new features. Many of these features have been requested by our
customers for years.&lt;/p&gt;

&lt;p&gt;(Spoiler alert: Calcapp Creator is finally getting support for undo and redo, an
editor for data tables, formulas that perform actions when buttons are pressed,
lots of new button types and much-improved formula editing, not to mention lots
of quality-of-life improvements. For more, read the blog posts linked to above.)&lt;/p&gt;

&lt;p&gt;So, why did we decide to include all these features in a single big release
instead of releasing them individually? To answer that, let’s step back and
consider what you get with your subscription.&lt;/p&gt;

&lt;h2 id=&quot;whats-in-a-subscription&quot;&gt;What’s in a subscription?&lt;/h2&gt;

&lt;p&gt;Calcapp is licenced on a subscription basis, meaning that you pay us a monthly
or annual fee to get access. Here’s what you’re getting for your money:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Reliable servers.&lt;/strong&gt; Your users should have unimpeded access to your apps,
and you should be able to update them with no downtime. It’s a rare week when
we don’t achieve 100% uptime.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Timely bug fixes.&lt;/strong&gt; We constantly fix bugs to ensure a smooth experience. In
2020, we had to &lt;a href=&quot;/blog/2020/04/02/offline.html&quot;&gt;rewrite our support for offline apps&lt;/a&gt; due to changes
in web browser technology. Our customers didn’t notice the difference, and
that’s how it should be.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Support.&lt;/strong&gt; We offer assistance, troubleshooting and guidance as part of your
 subscription. Need help adapting or troubleshooting your app? Just &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;write us
 an email&lt;/a&gt;, or open the chat window.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;New features.&lt;/strong&gt; We always strive to improve Calcapp with new features that
enhance your experience and make possible new kinds of apps.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;upcoming-changes-to-our-subscription-plans&quot;&gt;Upcoming changes to our subscription plans&lt;/h2&gt;

&lt;p&gt;Our new release will introduce higher-priced subscription plans. If you don’t
explicitly upgrade your apps to the new plans, they will remain on the original
plans, at the original price. That means that you won’t see your costs go up
unless you change to one of the new plans.&lt;/p&gt;

&lt;p&gt;We &lt;a href=&quot;/blog/2019/04/12/paid-plans.html&quot;&gt;introduced paid plans over four years ago&lt;/a&gt; and we have never
raised our prices since then. Once our next release is complete, Calcapp will be
a significantly better product than it was in 2019, and it will continue to
improve. We offer features not found elsewhere, including the &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;best formula
engine in the business&lt;/a&gt;, yet remain more affordable than the
competition. We think we can justify more expensive plans on the basis of
features alone.&lt;/p&gt;

&lt;p&gt;Also, our operational costs have gone up over the past year, and a revenue boost
would be welcome. We understand that many of our customers are in the same boat,
though, and we’d like not to add to any financial woes you may be experiencing.&lt;/p&gt;

&lt;p&gt;That’s why it’s important to us that if you make no changes to your
subscription, your prices won’t go up. It’s our way of saying “thank you” to our
existing customers, who have enabled us to work full-time on our favorite
project.&lt;/p&gt;

&lt;p&gt;Some of the new features we plan to deliver will be exclusive to our new plans,
meaning you’ll need to upgrade in order to access them.&lt;/p&gt;

&lt;p&gt;At the same time, we want to ensure that you continue to receive significant
value from your subscription, even if you choose not to upgrade. As noted above,
one of the pillars of our subscriptions is getting access to new features for as
long as you subscribe, and we don’t want that to change, no matter if you
upgrade to a new plan or not.&lt;/p&gt;

&lt;p&gt;That brings us to why we decided to put so many new features in our upcoming
release. The reason is that we want to deliver new features not only for
customers who choose to upgrade, but also to customers who elect not to. And
that requires a big release.&lt;/p&gt;

&lt;p&gt;You won’t be able to move your apps to our existing subscription plans once our
new release is out. If you want to lock in the lower prices, be sure to make all
subscription changes as soon as possible.&lt;/p&gt;

&lt;h2 id=&quot;beta-testers-needed&quot;&gt;Beta testers needed&lt;/h2&gt;

&lt;p&gt;When we started charging for Calcapp in 2019, it had been in beta since
early 2016. That long beta period helped us deliver a rock-solid product.&lt;/p&gt;

&lt;p&gt;Considering the ambitious nature of our new release, we believe a new beta
program is necessary to ensure it meets our standards. Do you want early access
to the new release, to help us identify bugs before we ship? If so, please &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;get
in touch&lt;/a&gt; with us!&lt;/p&gt;

</description>
        <pubDate>Fri, 02 Jun 2023 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/06/02/update.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/06/02/update.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Tip: Easily copy and paste fields between apps</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  When copying and pasting fields and screens from one app to another, it really
  helps if both are displayed side-by-side. This tip explores how to achive
  this.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;With Calcapp Creator, you can &lt;a href=&quot;/blog/2017/06/26/copy-paste.html&quot;&gt;copy and paste&lt;/a&gt; not just individual
fields, but also entire screens, including all the screens that follow them.
That means that it’s easy to copy parts of an app, or even the entire app, to
another app.&lt;/p&gt;

&lt;p&gt;However, it may not be apparent that you don’t need to close the app you’re
copying data from and then open the app you want to copy the data to. In fact,
you can keep both apps open at the same time, which saves a lot of time.&lt;/p&gt;

&lt;p&gt;You can do this by opening Calcapp Creator in separate tabs in your web browser,
but our favorite way of doing this is to have two apps open in two separate
windows, displayed side-by-side:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2023-04-12-copy-paste-between-apps/side-by-side.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2023-04-12-copy-paste-between-apps/side-by-side.png&quot; alt=&quot;Pasting from one app to another, displayed in separate windows&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(The one thing you can’t do with this feature is to copy and paste fields and
screens from one screen of the app to another screen of the same app.)&lt;/p&gt;

&lt;p&gt;To get two windows to appear side-by-side, you can either line them up manually,
or use a feature provided by your operating system, if available. Windows 10 and
Windows 11, for instance, support &lt;a href=&quot;https://support.microsoft.com/en-us/windows/snap-your-windows-885a9b1e-a983-a3b1-16cd-c531795e6241&quot;&gt;snapping your windows&lt;/a&gt; to
achieve this effect, and macOS supports &lt;a href=&quot;https://support.apple.com/en-us/HT204948&quot;&gt;Split View&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Wed, 12 Apr 2023 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/04/12/copy-paste-between-apps.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/04/12/copy-paste-between-apps.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Decide which image to show with a formula</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Conveying a calculated result by showing a specific image in your app can help
  improve its usability. This concise tip explores this simple technique.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Decide%20which%20image%20to%20show%20with%20a%20formula
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Using a formula to present a result, in the form of a number field or a text
field, is straight-forward. What if you instead want to convey a result by
showing a specific image? Luckily, deciding which image to show using a formula
is not only possible, but easy to do.&lt;/p&gt;

&lt;p&gt;Imagine an app intended for warehouse staff, who need to retrieve an item,
select an appropriate package for it and then make sure that it reaches its
intended destination. An app is perfect here — imagine a staff member who
enters the characteristics of the item, including its dimensions, into an app
and is shown visually what packaging to use.&lt;/p&gt;

&lt;p&gt;Here’s an app that uses a simple text drop-down field to determine what image to
show:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 580px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=ackw8s&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;Every image is part of a separate text box (which can include more information,
such as an image caption). The app above associates separate formulas with the
&lt;span class=&quot;link property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; properties of the three text boxes.&lt;/p&gt;

&lt;p&gt;There is also a text drop-down field, named &lt;em&gt;ImageSelector&lt;/em&gt;, which determines
which image is shown. It contains three items, which you need to reference from
the formulas.&lt;/p&gt;

&lt;p&gt;Here’s the first Visible formula, which determines if the first text box should
be shown:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;ImageSelector &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Mountain&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;ImageSelector &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Mountain&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Use similar formulas for the other images. The text on the right-hand side of
&lt;span class=&quot;link binaryOperator&quot; name=&quot;=&quot;&gt;=&lt;/span&gt; must match the text of the text drop-down field.&lt;/p&gt;

&lt;p&gt;To add a text box, press &lt;strong&gt;Add text&lt;/strong&gt; in the main designer and then &lt;a href=&quot;/blog/2018/06/01/text-box-images.html&quot;&gt;add an
image&lt;/a&gt; to it. To edit a Visible formula, press the button with
a gray &lt;strong&gt;fx&lt;/strong&gt; symbol next to &lt;strong&gt;Visible&lt;/strong&gt; in the inspector.&lt;/p&gt;

</description>
        <pubDate>Sun, 05 Feb 2023 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2023/02/05/conditional-images.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2023/02/05/conditional-images.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Our next release has been delayed</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our next release has been slightly delayed, because we are adding new features
  to it. Two of those features are announced in this post, including a better
  formula editing experience and an easy way to check multiple items in Calcapp
  Creator.
&lt;/div&gt;

&lt;p&gt;In September, &lt;a href=&quot;/blog/2022/09/11/update.html&quot;&gt;we announced&lt;/a&gt; a slew of new features for our upcoming
release and noted that we expected to release it “in the coming months.”&lt;/p&gt;

&lt;p&gt;However, in close consultation with our customers, we have decided to
incorporate a fair number of additional features into our next release. The good
news is that it will be our biggest release ever, with many new features that
enable new types of apps to be built, along with a host of improvements to the
app authoring experience. The bad news is that you will need to wait a while
longer before you get access to it.&lt;/p&gt;

&lt;p&gt;In addition to the features we &lt;a href=&quot;/blog/2022/09/11/update.html&quot;&gt;previously teased&lt;/a&gt;, these new features
are also slated to be part of our next release:&lt;/p&gt;

&lt;h2 id=&quot;intelligent-formula-completion&quot;&gt;Intelligent formula completion&lt;/h2&gt;

&lt;p&gt;In November last year, we &lt;a href=&quot;/blog/2021/11/12/documentation.html&quot;&gt;dramatically improved our formula
documentation&lt;/a&gt;. It contains thousands of formula examples, which
you can copy and paste into the formula field in Calcapp Creator.&lt;/p&gt;

&lt;p&gt;Currently, the documentation is a part of our main website, and you can’t gain
access to it from inside of the app designer. Moreover, when you type formulas,
there is no help or guidance to be had. While we’ve worked hard to make the
error messages presented to you as clear as possible, there is no help to be had
while typing formulas in Calcapp Creator itself.&lt;/p&gt;

&lt;p&gt;Spreadsheets were much the same way in years past, but have recently become more
helpful. (Microsoft calls their implementation in Excel
&lt;a href=&quot;https://support.microsoft.com/en-us/office/use-autocomplete-when-entering-formulas-d51ef125-60ff-438f-ba26-d9bd6b363bbe&quot;&gt;AutoComplete&lt;/a&gt; and Google Sheets offers a similar feature.)
You get helpful suggestions when typing formulas, and snippets of documentation
appear when you supply functions with their parameters. Crucially, you are
provided with the name of the current function parameter, meaning that
memorizing the parameter order is a thing of the past.&lt;/p&gt;

&lt;p&gt;Calcapp will gain a similar feature set in our next release. When you type, a
box will appear allowing you to easily insert function names, parameter names,
field names and more:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/autocomplete.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/autocomplete.png&quot; alt=&quot;A box allowing for function names and the like to be inserted&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you type the name of a screen (or select it from the box) followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt;,
you’ll be given the opportunity to select which of its fields to reference:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/autocomplete-screen.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/autocomplete-screen.png&quot; alt=&quot;A box allowing for the items of screens to be inserted&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you type the name of a screen, a field or another item, followed by
&lt;span class=&quot;formula decimalpoint&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;,&lt;/span&gt;, you get to select a property to reference:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/autocomplete-properties.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/autocomplete-properties.png&quot; alt=&quot;A box allowing for properties to be inserted&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, if you edit a parameter to a function, a popup appears showing exactly
which parameter you’re editing, along with a snippet from the documentation and
a link to the full text:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/popup.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/popup.png&quot; alt=&quot;A popup with information on functions and their parameters&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The formula editing experience has been upgraded in other ways as well,
including bracket matching (when the cursor is by a parenthesis or an array
brace, the corresponding parenthesis or array brace “on the other side” is
highlighted), the ability to insert line breaks and more.&lt;/p&gt;

&lt;h2 id=&quot;selecting-multiple-items-in-calcapp-creator&quot;&gt;Selecting multiple items in Calcapp Creator&lt;/h2&gt;

&lt;p&gt;When you’re creating an app, checking multiple fields or other items is often
the best way to quickly make changes. You can remove multiple items at once, and
edit properties of multiple items at once. For instance, if you check ten number
fields, you can make them all enabled or disabled, without having to make these
changes individually.&lt;/p&gt;

&lt;p&gt;In form screens, fields, buttons and text boxes are part of form groups. When
you check a form group, all its constituent items are also checked, and vice
versa when you uncheck the form group. We envisioned this as a way to quickly
check multiple items.&lt;/p&gt;

&lt;p&gt;However, sometimes you need to quickly check multiple items, that just happen to
be adjacent, and are not necessarily part of the same form group. Also,
sometimes you want to check a form group, without checking its constituent
items. (If you remove just a form group and not its items, for instance, its
items are merged into the form group above it.)&lt;/p&gt;

&lt;p&gt;The standard way of enabling multiple adjacent items to be checked is to press
and hold the Shift key while checking items, and this is exactly the workflow
that Calcapp Creator will soon support. As some of our Calcapp Creator users are
on touch devices, there will also be a button you can toggle to access the new
feature:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/multi-check.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/multi-check.png&quot; alt=&quot;Checking multiple items will soon be easy&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;a-preview-of-the-new-data-editor&quot;&gt;A preview of the new data editor&lt;/h2&gt;

&lt;p&gt;One of our most-requested features ever is the ability to easily handle tabular
data. &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;Our November release last year&lt;/a&gt; added support for
the powerful &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; function, but you still had to use a clunky
external app to convert your tabular data for use with your apps (and to this
day, you still do).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2022/09/11/update.html&quot;&gt;As noted in September&lt;/a&gt;, our new data editor will soon make this process
go a lot smoother. We have essentially completed it, so here are four
screenshots of it to whet your appetite:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/data-editor1.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/data-editor1.png&quot; alt=&quot;A screenshot of the new data editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/data-editor2.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/data-editor2.png&quot; alt=&quot;A screenshot of the new data editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/data-editor3.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/data-editor3.png&quot; alt=&quot;A screenshot of the new data editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-12-21-delay/data-editor4.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-12-21-delay/data-editor4.png&quot; alt=&quot;A screenshot of the new data editor&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is shaping up to be our biggest release yet, and we’re working hard to
deliver it to you as soon are we’re able.&lt;/p&gt;

</description>
        <pubDate>Wed, 21 Dec 2022 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2022/12/21/delay.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2022/12/21/delay.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Tip: Use iteration with REDUCE</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Iteration means that a value is calculated by performing a number of steps,
  where the result of the previous step is fed into the current step. Use REDUCE
  to implement iteration with Calcapp.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;When solving a math problem, there are two broad ways to go about doing it: a
direct way, and using &lt;em&gt;iteration&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The simplest possible example is probably multiplying a number by an integer.
You can either use multiplication directly (say, &lt;span class=&quot;formula decimalpoint&quot;&gt;9 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;9 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 3&lt;/span&gt;), or
you can iteratively add nine together three times (&lt;span class=&quot;formula decimalpoint&quot;&gt;9 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 9 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 9&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;9 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 9 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 9&lt;/span&gt;). Both methods arrive at the same result, though the direct method is easier
and faster.&lt;/p&gt;

&lt;p&gt;However, it isn’t always easy, or even possible, to use a direct method, meaning
iteration may be your only option. Calcapp’s &lt;span class=&quot;link function&quot; name=&quot;XIRR&quot;&gt;XIRR&lt;/span&gt; function, for
instance, uses iteration to calculate its result.&lt;/p&gt;

&lt;h2 id=&quot;using-iteration-in-excel&quot;&gt;Using iteration in Excel&lt;/h2&gt;

&lt;p&gt;Iteration is fairly easy to use in a spreadsheet like Microsoft Excel. Let’s say
that we have a starting balance of $10,000 and that we gain an unrealistic one
percent in interest every day. We wish to calculate what our balance is on every
day for the next 28 days.&lt;/p&gt;

&lt;p&gt;(For the moment, let’s ignore the fact that there is a straight-forward direct
way of calculating the result, using either the &lt;span class=&quot;link function&quot; name=&quot;FV&quot;&gt;FV&lt;/span&gt; function or
the &lt;span class=&quot;link binaryOperator&quot; name=&quot;^&quot;&gt;^&lt;/span&gt; operator.)&lt;/p&gt;

&lt;p&gt;In Excel, we have a starting balance in cell B1:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2022-11-15-iteration/excel.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2022-11-15-iteration/excel.png&quot; alt=&quot;Solving a problem using iteration in Excel&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The formula of cell B2 references the value in cell B1 and multiplies
it by  101% (&lt;span class=&quot;formula decimalpoint&quot;&gt;B1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;B1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;&lt;/span&gt;). The formula of cell
B3, in turn, references the value in cell B2 and multiplies it by 101%
(&lt;span class=&quot;formula decimalpoint&quot;&gt;B2 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;B2 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;&lt;/span&gt;).&lt;/p&gt;

&lt;p&gt;It continues like that, all the way to day 28. Excel makes it easy to create all
these formulas, using its &lt;a href=&quot;https://support.microsoft.com/en-us/office/fill-data-automatically-in-worksheet-cells-74e31bdd-d993-45da-aa82-35a236c5b5db&quot;&gt;Auto Fill feature&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;using-iteration-in-calcapp&quot;&gt;Using iteration in Calcapp&lt;/h2&gt;

&lt;p&gt;If we have solved a problem in Excel using iteration, how can we get Calcapp to
calculate the same results?&lt;/p&gt;

&lt;p&gt;One way would be to add many hidden fields to a form screen, using the exact
same type of formulas as used with Excel. While that works for a few hundred
iterations, you will find that adding thousands or even tens of thousands of
hidden fields to an app makes Calcapp Creator, our app designer, sluggish
(though the resulting apps tend to run well). Also, duplicating and subtly
changing thousands of formulas — without the benefit of Auto Fill — means a lot
of tedious, repetitive work.&lt;/p&gt;

&lt;p&gt;A better solution is to use the &lt;span class=&quot;link function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt; function, which we
&lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;introduced last year&lt;/a&gt;. (Excel &lt;a href=&quot;https://techcommunity.microsoft.com/t5/excel-blog/announcing-lambda-helper-functions-lambdas-as-arguments-and-more/ba-p/2576648&quot;&gt;gained initial support
for REDUCE&lt;/a&gt; a few months before Calcapp did, which was too late
for us to be influenced by Microsoft’s work. That means that they are slightly
different.)&lt;/p&gt;

&lt;p&gt;This function reduces a value to a single value using a user-supplied formula.
It takes &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;an array&lt;/a&gt; as its first parameter and then runs the formula
fragment given as its second parameter once for every element of the array.&lt;/p&gt;

&lt;p&gt;REDUCE keeps track of the value returned from the second parameter and adds it
to its so-called &lt;em&gt;accumulator&lt;/em&gt; (which is initially set to the value you provide
as the third parameter). The result returned from REDUCE is the value of the
accumulator after all elements of the array have been processed.&lt;/p&gt;

&lt;p&gt;This formula calculates the sum of all values of the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3 }&lt;/span&gt;, 6:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;({ 1, 2, 3 }, Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Value, 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;({ 1; 2; 3 }; Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Value; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The initial accumulator is set to 0 (the third parameter above). The second
parameter, &lt;span class=&quot;formula decimalpoint&quot;&gt;Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Value&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; Value&lt;/span&gt;, is then invoked with
&lt;code&gt;Value&lt;/code&gt; set to 1, which causes the second parameter to return
&lt;span class=&quot;formula decimalpoint&quot;&gt;0 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;0 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1&lt;/span&gt;. As a result, REDUCE stores 1 as the accumulator
before continuing.&lt;/p&gt;

&lt;p&gt;REDUCE then invokes the second parameter once more, this time with
&lt;code&gt;Accumulator&lt;/code&gt; set to 1 and &lt;code&gt;Value&lt;/code&gt; set to 2. This time
around, the second parameter returns &lt;span class=&quot;formula decimalpoint&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3&lt;/span&gt;,
which again is stored as the accumulator.&lt;/p&gt;

&lt;p&gt;Finally, the second parameter is invoked with &lt;code&gt;Accumulator&lt;/code&gt; and &lt;code&gt;Value&lt;/code&gt; both set to 3, meaning that the second parameter returns
&lt;span class=&quot;formula decimalpoint&quot;&gt;3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 6&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 6&lt;/span&gt;, which is also the value returned from REDUCE.&lt;/p&gt;

&lt;p&gt;(If you want to learn how to calculate averages, minimum and maximum values and
more, refer to &lt;span class=&quot;link function&quot; name=&quot;REDUCE&quot;&gt;our REDUCE documentation&lt;/span&gt;.)&lt;/p&gt;

&lt;p&gt;We can use the same technique to calculate interest. This formula returns the
balance on day 28 — $13,212.91 — provided that the interest is set to one
percent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;(28), Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;, 10000)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;(28); Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;; 10000)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The goal is to get REDUCE to run the second parameter 28 times. In order for
that to happen, the first parameter must be an array with 28 elements. The
&lt;span class=&quot;link function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt; function is used to return such an array. (Only the
size of the array is important, not the values of its elements, which are not
used here.)&lt;/p&gt;

&lt;h2 id=&quot;returning-all-intermediate-values-as-an-array&quot;&gt;Returning all intermediate values as an array&lt;/h2&gt;

&lt;p&gt;The formula above and the Excel spreadsheet both return the same number for
day 28. However, what if we also need to retain all the intermediate values?
The goal is for an array to be returned containing these values (exactly
matching the Excel spreadsheet):&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 10000, 10100, 10201, 10303.01, 10406.04, 10510.10, 10615.20, 10721.35, 10828.57, 10936.85, 11046.22, 11156.68, 11268.25, 11380.93, 11494.74, 11609.69, 11725.79, 11843.04, 11961.47, 12081.09, 12201.90, 12323.92, 12447.16, 12571.63, 12697.35, 12824.32, 12952.56, 13082.09, 13212.91 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 10000; 10100; 10201; 10303,01; 10406,04; 10510,10; 10615,20; 10721,35; 10828,57; 10936,85; 11046,22; 11156,68; 11268,25; 11380,93; 11494,74; 11609,69; 11725,79; 11843,04; 11961,47; 12081,09; 12201,90; 12323,92; 12447,16; 12571,63; 12697,35; 12824,32; 12952,56; 13082,09; 13212,91 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Here’s a version of the formula above that does just that:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;(28), Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Accumulator, Index) &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;, { 10000 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;(28); Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Accumulator; Index) &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;; { 10000 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;There’s a lot going on above, so let’s take it one step at a time.&lt;/p&gt;

&lt;p&gt;First, the initial accumulator, in the form of the third parameter, is set to
&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 10000 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 10000 }&lt;/span&gt; instead of &lt;code&gt;10000&lt;/code&gt;. In other words, it is set
to an array containing the single element &lt;code&gt;10000&lt;/code&gt;. This enables REDUCE to
return an array of numbers instead of a single number.&lt;/p&gt;

&lt;p&gt;When the second parameter accesses the &lt;code&gt;Accumulator&lt;/code&gt; value, it is an
array, initially containing just &lt;code&gt;10000&lt;/code&gt;. The goal is to add elements to
this array at the very end. To achieve this, &lt;span class=&quot;link binaryOperator&quot; name=&quot;|&quot;&gt;|&lt;/span&gt; is used, which is
formally known as the &lt;em&gt;array concatenation operator&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link binaryOperator&quot; name=&quot;|&quot;&gt;|&lt;/span&gt; is similar to &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt;, which joins text strings
together. This formula returns “Test”:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;Te&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;st&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;Te&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;st&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns &lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3, 4 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3; 4 }&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 3, 4 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 3; 4 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The part on the right-hand side can also be a single value. This formula returns
&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3 }&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; 3&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In the REDUCE formula above, &lt;span class=&quot;link binaryOperator&quot; name=&quot;|&quot;&gt;|&lt;/span&gt; is used to add elements to the
array which is ultimately returned. &lt;code&gt;Accumulator&lt;/code&gt; is initially set to
&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 10000 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 10000 }&lt;/span&gt;, meaning that what &lt;code&gt;|&lt;/code&gt; does is that it adds
an element that follows the first element, &lt;code&gt;10000&lt;/code&gt;. When the second
parameter is run subsequently, every new calculated value is added to the end of
the accumulator array.&lt;/p&gt;

&lt;p&gt;The final part of the puzzle is how we calculate the next element to add to the
array. The first REDUCE formula, introduced at the beginning of this post,
multiplied the last value by 101 percent, and this is what we need to do here
too.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Accumulator&lt;/code&gt; value accessible to the second parameter, though, no
longer represents the running total. Instead, the accumulator is an array of all
values calculated so far. What we need is the last element of this array.&lt;/p&gt;

&lt;p&gt;In order to retrieve it, we use this formula fragment:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Accumulator, Index)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Accumulator; Index)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt; function returns an element from an array at the given
index. &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;({ 10, 20, 30 }, 2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;({ 10; 20; 30 }; 2)&lt;/span&gt;, for instance, returns 20.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Index&lt;/code&gt; value available to the second parameter is a special value
indicating the position of the array element currently being processed. It
happens to be equal to the size of the &lt;code&gt;Accumulator&lt;/code&gt; array. As a result,
the formula above returns the last element of the array, which is what we want.&lt;/p&gt;

&lt;p&gt;The final order of business is to multiply this value by 101 percent, after
which REDUCE returns the array containing the balances of all days.&lt;/p&gt;

&lt;p&gt;To access the balance of a specific day, use INDEX. Let’s assume that there is a
field named &lt;em&gt;DayNumber&lt;/em&gt; (possibly with a &lt;a href=&quot;/blog/2018/01/10/sliders.html&quot;&gt;slider&lt;/a&gt;), holding the number
of the day the user is interested in. This final formula returns the balance on
that particular day:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;(28), Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Accumulator, Index) &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;, { 10000 }), DayNumber)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;(28); Accumulator &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;(Accumulator; Index) &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 101&lt;span class=&quot;unaryOperator&quot; name=&quot;PERCENTAGE&quot;&gt;%&lt;/span&gt;; { 10000 }); DayNumber)&lt;/span&gt;&lt;/p&gt;

</description>
        <pubDate>Tue, 15 Nov 2022 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2022/11/15/iteration.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2022/11/15/iteration.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Action formulas and a tabular data editor are coming soon</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Calcapp will become significantly better in the coming months. Action formulas
  will enable buttons to run formulas, and a new data editor will allow you to
  easily incorporate spreadsheet data into your apps.
&lt;/div&gt;

&lt;p&gt;When we released our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;big update to our formula engine&lt;/a&gt;
in November last year, we promised that more features related to the formula
engine were coming. Today, we’d like to announce that we’re nearing the end of
our current development cycle, and that these features will be released in the
coming months.&lt;/p&gt;

&lt;p&gt;Here’s a sneak preview of the new features:&lt;/p&gt;

&lt;h2 id=&quot;action-formulas&quot;&gt;Action formulas&lt;/h2&gt;

&lt;p&gt;We have teased &lt;em&gt;action formulas&lt;/em&gt; &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;since 2020&lt;/a&gt;, and they are finally
almost ready to ship. At its core, an action formula has access to special
functions which perform actions. Our next release will allow you to create
special buttons that run these formulas when the button is pressed.&lt;/p&gt;

&lt;p&gt;These are some of the things you’ll be able to do with an action formula:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Send a report, but only if the entered data is valid. Otherwise, show the user
an alert box.&lt;/li&gt;
  &lt;li&gt;Ask the user a series of questions, before sending a report incorporating
the entered answers.&lt;/li&gt;
  &lt;li&gt;Create a button that calculates values only when pressed.&lt;/li&gt;
  &lt;li&gt;Send multiple reports, incorporating different information, to different email
addresses.&lt;/li&gt;
  &lt;li&gt;Open a report on the user’s device, while also sending a message to the team’s
internal Slack channel. (Integration with Slack, and other third-party
services like Google Sheets, Excel and Salesforce will require a third-party
service like &lt;a href=&quot;https://www.zapier.com&quot;&gt;Zapier&lt;/a&gt;, just like today.)&lt;/li&gt;
  &lt;li&gt;Reset all fields, but only if the user first consents by pressing a button to
that effect in a message box. Then, move the user back to the first screen,
and ensure that previously-hidden text boxes are once more visible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This action formula asks the user for their name and greets them once the name
has been entered:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AWAIT(PROMPT(&quot;What&apos;s your name?&quot;), BANNER(&quot;Hi &quot; &amp;amp; Result &amp;amp; &quot;!&quot;))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This action formula sends a report, containing all fields of the app, and shows
a banner if the report could not be sent successfully:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AWAIT(EMAILREPORT({ App }, &quot;test@example.com&quot;), OnFailure: BANNER(&quot;Could not
send report&quot;))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, this action formula asks the user to enter a number, and once the user
has done so, the entered number and the entered number divided by two are shown
in a banner:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AWAIT(PROMPT.NUMBER(&quot;Enter number:&quot;), BANNER(&quot;Half of &quot; &amp;amp; Result &amp;amp; &quot; is &quot; &amp;amp;
(Result / 2) &amp;amp; &quot;.&quot;))&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;many-more-actions&quot;&gt;Many more actions&lt;/h2&gt;

&lt;p&gt;Today, buttons can only email and open reports, reset fields and send data to
third-party services like Zapier. Soon, many more actions will be available:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Copy text to the system clipboard.&lt;/li&gt;
  &lt;li&gt;Show an alert box, which users need to dismiss by pressing a button.&lt;/li&gt;
  &lt;li&gt;Open an email compose window on the user’s device, with pre-filled fields.&lt;/li&gt;
  &lt;li&gt;Open a text message (SMS) compose window, again with pre-filled fields.&lt;/li&gt;
  &lt;li&gt;Dial a phone number.&lt;/li&gt;
  &lt;li&gt;Open a web page in the user’s web browser.&lt;/li&gt;
  &lt;li&gt;Move forward to a screen you determine.&lt;/li&gt;
  &lt;li&gt;Move backward to a previously-visited screen you determine.&lt;/li&gt;
  &lt;li&gt;Open a map using the user’s installed map app, or on the web.&lt;/li&gt;
  &lt;li&gt;Print the current screen or save it as a PDF document.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the properties of these new buttons are calculated properties, meaning
that their values can be determined using formulas.&lt;/p&gt;

&lt;p&gt;Also, the existing buttons have also been revamped, so that many more of their
properties can be determined using formulas. For instance, you’ll be able to
determine if a report is sent as a CSV file or as a PDF document using a
formula.&lt;/p&gt;

&lt;p&gt;All the new features are also available to action formulas, which support even
more features:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Show a banner message, which disappears automatically.&lt;/li&gt;
  &lt;li&gt;Ask the user for confirmation.&lt;/li&gt;
  &lt;li&gt;Ask the user to enter a text string or a number, which can then be used to
take further action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Action formulas will also be able to assign any value to any property using the
new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; operator. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1.Visible := FALSE&lt;/code&gt; will hide &lt;em&gt;Field1&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;named-parameters&quot;&gt;Named parameters&lt;/h2&gt;

&lt;p&gt;Some functions accept a large number of parameters, which can make formulas hard
to read. Our new release includes support for &lt;em&gt;named parameters&lt;/em&gt;, allowing you
to precede a parameter value with its name, followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For instance, these two formulas will be equivalent:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FORMATNUMBER(23, 2, 2, FALSE, 1, FALSE, &quot;$&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FORMATNUMBER(Number: 23, MinimumNumberOfDecimalPlaces: 2,
MaximumNumberOfDecimalPlaces: 2, OmitThousandsSeparators: FALSE,
MinimumNumberOfIntegerDigits: 1, UseAccountingStyle: FALSE, LeadingUnit: &quot;$&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;All parameters don’t need to be named, but once a parameter has been named, the
remaining parameters must also be named.&lt;/p&gt;

&lt;p&gt;Named parameters make it possible to provide parameters out-of-order and to omit
optional parameters that normally would have been expected to precede a
parameter, had it not been named. Omitted optional parameters use default
values.&lt;/p&gt;

&lt;p&gt;The formula above uses default values for all parameters other than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Number&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LeadingUnit&lt;/code&gt;. As such, those optional parameters can be removed from the
formula:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FORMATNUMBER(23, LeadingUnit: &quot;$&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We suggest that you use named parameters when they help make a formula easier to
read.&lt;/p&gt;

&lt;p&gt;Named parameters were added to Calcapp to make existing functions like
FORMATNUMBER easier to use, but also in consideration of new functions like
EMAILREPORT and OPENREPORT. Those functions support a very large number of
optional parameters, and named parameters will enable you to only provide the
parameters you care about, omitting the rest.&lt;/p&gt;

&lt;h2 id=&quot;the-let-function&quot;&gt;The LET function&lt;/h2&gt;

&lt;p&gt;The new LET function, which is also &lt;a href=&quot;https://support.microsoft.com/en-us/office/let-function-34842dd8-b92b-4d3f-b325-b8b8f9908999&quot;&gt;part of Excel 2021&lt;/a&gt;, allows you
to name values you use in formulas. That means that you no longer need to repeat
calculations that otherwise would have appeared multiple times, making formulas
run faster and making them shorter and easier to read.&lt;/p&gt;

&lt;p&gt;This formula should be read as “give X the value 2, Y the value 4 plus X, and
return Y divided by two”:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LET(X := 2, Y := 4 + X, Y / 2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;By assigning names to values, you can make formulas easier to read. If a formula
consists of many moving parts, being able to name values serves as valuable
documentation.&lt;/p&gt;

&lt;p&gt;This is especially important for apps maintained by multiple people, allowing
other members of your organization to more easily understand how your formulas
work. Being able to name values has been available to traditional software
developers for decades.&lt;/p&gt;

&lt;p&gt;LET adds a lot of value to regular formulas, but works especially well with
action formulas. If you need to, say, send a report with certain values and
reset them afterwards to blank values, doing so without LET invariably leads to
formula duplication.&lt;/p&gt;

&lt;p&gt;Here’s an attempt without LET:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EMAILREPORT({ Field1, Field3:Field10 }, &quot;test@example.com&quot;); RESET.BLANK({
Field1, Field3:Field10 })&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With LET, there is no need to duplicate what fields to send and reset:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LET(Fields := { Field1, Field3:Field10 }, EMAILREPORT(Fields,
&quot;test@example.com&quot;); RESET.BLANK(Fields))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Being able to type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; to assign values to fields is a Calcapp extension. Excel
2021 requires that you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; instead (depending on your language
settings). We think that using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; makes formulas easier to read, but you’re
also welcome to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; if you’re used to that syntax from Excel.&lt;/p&gt;

&lt;h2 id=&quot;named-values&quot;&gt;Named values&lt;/h2&gt;

&lt;p&gt;Calcapp gained support for &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden fields&lt;/a&gt; way back in 2016. They
allow you to assign names to calculations and use them from other formulas. This
is somewhat similar to LET, but LET allows you to name values that are only
accessible from a single formula, whereas hidden fields are accessible to the
entire app.&lt;/p&gt;

&lt;p&gt;Hidden fields have one major drawback, though: they can only represent numbers,
logical values and text strings.&lt;/p&gt;

&lt;p&gt;That wasn’t a problem before our new formula engine was introduced last year,
because before that time, Calcapp actually only handled numbers, logical values
and text strings. Today, formulas can reference many more things, including
fields, buttons and — most importantly – arrays.&lt;/p&gt;

&lt;p&gt;Simply put, there is currently no way to name an array and make it available to
other parts of your app. That means that arrays have to be duplicated left and
right in your app, which is especially worrisome for arrays that contain a lot
of data (possibly converted from a spreadsheet using &lt;a href=&quot;/blog/2021/11/12/xlookup-generator.html&quot;&gt;our
app&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;With named values, those issues go away, as a named value can represent anything
a formula can return in Calcapp, including arrays. They are, by default, hidden,
but you can make them visible to &lt;a href=&quot;/blog/2017/04/03/debug-mode.html&quot;&gt;help spot problems in your app&lt;/a&gt;
(optionally using a formula).&lt;/p&gt;

&lt;p&gt;As such, visualizing arrays, &lt;a href=&quot;/blog/2021/11/12/debug-arrays.html&quot;&gt;as suggested by this tip&lt;/a&gt;, will no
longer require text fields and the &lt;span class=&quot;link function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt; function.&lt;/p&gt;

&lt;h2 id=&quot;an-editor-for-your-tabular-data&quot;&gt;An editor for your tabular data&lt;/h2&gt;

&lt;p&gt;Historically, we have never done a very good job of helping you work with
data maintained as tables in a spreadsheet. &lt;a href=&quot;/blog/2018/04/06/tabular-data-drop-downs.html&quot;&gt;In 2018&lt;/a&gt;,
we introduced the &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; function and the
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberDropDownField&quot; name=&quot;Index&quot;&gt;Index&lt;/span&gt; property of drop-down fields, allowing
values to be selected based on what value the user selected from a drop-down
field.&lt;/p&gt;

&lt;p&gt;That release also introduced &lt;a href=&quot;/blog/2018/04/06/column-converter.html&quot;&gt;a new app&lt;/a&gt;, written in Calcapp
using advanced new &lt;a href=&quot;/blog/2018/04/06/regular-expressions.html&quot;&gt;text processing functions&lt;/a&gt; introduced
just to make that app a reality. The app allows Calcapp authors to convert
spreadsheet tables to CHOOSE formulas, one column at a time.&lt;/p&gt;

&lt;p&gt;CHOOSE is a poor substitute for true table lookups, though. This issue was
finally rectified last year, when our new formula engine introduced support for
the new &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; function (which can do everything that HLOOKUP
and VLOOKUP can do). There was also &lt;a href=&quot;/blog/2021/11/12/xlookup-generator.html&quot;&gt;a new app&lt;/a&gt; for
generating XLOOKUP formulas from spreadsheet tables, requiring Calcapp authors
to copy and paste data, one column at a time.&lt;/p&gt;

&lt;p&gt;While having support for true table lookups is great, the status quo leaves much
to be desired. First, converting tabular data to formulas is time-consuming and
dull. Having to repeat the process every time the data needs to be updated makes
matters worse.&lt;/p&gt;

&lt;p&gt;Second, the tabular data can potentially be large, making apps slow to download
and use. If multiple formulas need to look up data, they need to repeat the same
table data. That means that when that data needs to be updated, it’s easy to
miss a formula, making for inconsistent, buggy apps.&lt;/p&gt;

&lt;p&gt;Thankfully, those concerns are soon a thing of the past. Our new release will
introduce a data editor, allowing you to copy and paste spreadsheet tables in
full to Calcapp Creator. When you need to update said data, you’ll be able to
bring up the same data editor and make edits either manually, or by pasting data
from your spreadsheet.&lt;/p&gt;

&lt;p&gt;The new data editor is powered by named values (see above). Every column
causes a new named value to be created (or altered), containing arrays
which can be passed directly to functions like &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;
and &lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;If you like, you can create screens that are not reachable by your users which
consist entirely of named values. Every such screen represents a table.&lt;/p&gt;

&lt;p&gt;Imagine a screen named &lt;em&gt;Employees&lt;/em&gt;, with the following named values (created
automatically from data by the data editor): &lt;em&gt;Name&lt;/em&gt; and &lt;em&gt;Salary&lt;/em&gt;. You’ll be able
to find the salary of an employee using this XLOOKUP formula:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XLOOKUP(Name, Employees!Name, Employees!Salary)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2020/04/02/calcapp-4.html#tabular-data&quot;&gt;Back in 2020&lt;/a&gt;, we promised much better support for
tabular data in a future Calcapp 4 product. While the new data editor goes some
way towards realizing those ambitions, it does not fully do so.&lt;/p&gt;

&lt;p&gt;Specifically, tables remain read-only, unable to incorporate changes made in the
app. If you want data entered in the app to be reflected in a spreadsheet table,
you need to use a third-party product, such as Zapier, with your app, and even
then, the app cannot reflect the entered data the next time it is started.&lt;/p&gt;

&lt;p&gt;We will soon begin to explore ways of making apps produced with Calcapp truly
data-aware.&lt;/p&gt;

&lt;h2 id=&quot;minor-feature-additions&quot;&gt;Minor feature additions&lt;/h2&gt;

&lt;p&gt;Today, all links opened from an app open in a new window or tab. This is
appropriate for stand-alone apps, but not always for apps embedded in an
existing website (where you may want links to open in the existing window or
tab).&lt;/p&gt;

&lt;p&gt;Our new release will make this behavior fully customizable. The selected
behavior will, for the time being, apply to all text box links, with no ability
to determine the behavior on a per-link basis. However, the new buttons that
open web pages will support selecting the behavior on a per-button basis, and
the corresponding action function BROWSE will also allow this behavior to be
determined at a more granular level.&lt;/p&gt;

&lt;p&gt;Finally, our new release will make the &lt;a href=&quot;/blog/2021/11/12/documentation.html&quot;&gt;new formula
documentation&lt;/a&gt; we introduced last year far more accessible.
Specifically, when you edit the formula of a property in Calcapp Creator, a
button will allow you to visit the documentation for that property directly.
Also, a link in the inspector will allow you to browse the documentation for the
element you’re editing.&lt;/p&gt;

&lt;p&gt;We think that this release, with its support for action formulas and an editor
for spreadsheet tables, has the potential to be even more important than &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;our
release from last year&lt;/a&gt;, which was our most ambitious
release to date. This release may not be bigger, strictly speaking, but it
arguably introduces features that are even more desirable than those we
introduced last year.&lt;/p&gt;

&lt;p&gt;Look for the new release in the coming months. Be sure to subscribe to our
newsletter (bring up the menu with your email address on it in Calcapp Creator
and select &lt;em&gt;Account settings…&lt;/em&gt;) to be notified when that happens.&lt;/p&gt;

</description>
        <pubDate>Sun, 11 Sep 2022 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2022/09/11/update.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2022/09/11/update.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Tip: Summarize switch field selections in a single sentence</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Can the switch field selections made by a user be summed up in a single text
  field sentence? Yes, and there are two ways to do it, one using old-style
  formulas and one using the new formula engine we introduced in November.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Summarize%20switch%20field%20selections%20in%20a%20single%20sentence
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;A customer recently got in touch and asked if it was possible to summarize the
switch field selections made by a user in a single text field. The answer is yes
— and what’s interesting is that there are two ways to do it, one using
classic Calcapp formulas, and one fully taking advantage of our new &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;formula
engine&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, let’s consider a sample app. Here, the user is asked to select which
weekdays they worked. The results are summarized in a text field:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 501px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=ps775&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;What’s interesting here are the formulas associated with the “Days worked”
text fields. Here’s the old-style formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;Monday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Thursday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Thursday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Friday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Friday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;, &quot;None.&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;Monday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Thursday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Thursday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Friday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Friday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;; &quot;None.&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;And here’s the formula that takes full advantage of the new formula engine:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday), &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;, FALSE, &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Monday:Friday, Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE).&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;, &quot;None.&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday); &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;; FALSE; &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Monday:Friday; Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE),&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;; &quot;None.&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We’ll go over the formulas in detail soon, but suffice to say that the new
formula is not only shorter, but also a lot less repetitive. For employees
potentially working seven days a week, we could easily add two new switch
fields, &lt;em&gt;Saturday&lt;/em&gt; and &lt;em&gt;Sunday&lt;/em&gt;, type &lt;span class=&quot;formula decimalpoint&quot;&gt;Monday:Sunday&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Monday:Sunday&lt;/span&gt; instead
of &lt;span class=&quot;formula decimalpoint&quot;&gt;Monday:Friday&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Monday:Friday&lt;/span&gt; in the formula and be done. With the
old-style formula, achieving the same end result would be a lot more work.&lt;/p&gt;

&lt;h2 id=&quot;dissecting-the-old-style-formula&quot;&gt;Dissecting the old-style formula&lt;/h2&gt;

&lt;p&gt;First, let’s look at the old-style formula to see why it works. Here it is
again:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;Monday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Thursday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Thursday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Friday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Friday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;, &quot;None.&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;Monday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Thursday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Thursday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Friday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Friday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;; &quot;None.&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;First, let’s strip away the second parameter to the first IF function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday, …, &quot;None.&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday; …, &quot;None.&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;What this formula does is that it uses the second parameter (here ellipsized as
&lt;code&gt;...&lt;/code&gt;) only if the user has selected one or several days. Otherwise, the
third parameter is selected and “None.” is used. &lt;span class=&quot;link binaryOperator&quot; name=&quot;||&quot;&gt;||&lt;/span&gt; is Calcapp’s
“logical or” operator, meaning that &lt;span class=&quot;formula decimalpoint&quot;&gt;Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday&lt;/span&gt; simply means &lt;em&gt;Monday or Tuesday or Wednesday or
Thursday or Friday.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s look at that second parameter to IF:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;Monday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Thursday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Thursday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Friday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Friday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;Monday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Thursday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Thursday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Friday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Friday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;Monday&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;Monday&quot;)&lt;/span&gt; is pretty self-explanatory — if the
switch field &lt;em&gt;Monday&lt;/em&gt; has been toggled to its “on” position, the text string
“Monday” is used. Otherwise, a blank value is used.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; is Calcapp’s concatenation operator, which joins text strings
together. That means that &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;a&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;b&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;a&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;b&quot;&lt;/span&gt; is a convoluted way of
writing &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;ab&quot;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Tuesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Tuesday&quot;)&lt;/span&gt; requires more of an
explanation. What’s &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday, &quot;, &quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday; &quot;, &quot;)&lt;/span&gt; doing there? Simply put,
it’s there to make sure that a comma separates “Monday” and “Tuesday”, but only
if the user has toggled the &lt;em&gt;Monday&lt;/em&gt; switch field to its “on” position.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday, &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Wednesday; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday; &quot;, &quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;Wednesday&quot;)&lt;/span&gt; is
similar. &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday, &quot;, &quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday; &quot;, &quot;)&lt;/span&gt; adds a leading comma
only if the user has selected &lt;em&gt;Monday&lt;/em&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;em&gt;Tuesday&lt;/em&gt;, that is, only if there
is text preceding “Wednesday”. Again, note the use of the “logical or” operator
&lt;span class=&quot;link binaryOperator&quot; name=&quot;||&quot;&gt;||&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;The remaining parts of the formula follow the same pattern.&lt;/p&gt;

&lt;h2 id=&quot;dissecting-the-new-style-formula&quot;&gt;Dissecting the new-style formula&lt;/h2&gt;

&lt;p&gt;The approach illustrated above may work acceptably if we only have five or seven
switch fields, but what if we have a hundred?&lt;/p&gt;

&lt;p&gt;The new formula engine provides a concise solution that performs identically to
the old-style approach. Here it is, again:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday), &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;, FALSE, &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Monday:Friday, Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE).&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;, &quot;None.&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday); &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;; FALSE; &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Monday:Friday; Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE),&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;; &quot;None.&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;First, let’s temporarily remove the second parameter to the first IF function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday), …, &quot;None.&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday); …, &quot;None.&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Like the old-style approach, this formula uses the text string “None.” if the
user has toggled none of the switch fields to an “on” position. Otherwise, it
uses the ellipsized second parameter.&lt;/p&gt;

&lt;p&gt;Essentially, this approach replaces &lt;span class=&quot;formula decimalpoint&quot;&gt;Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Monday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Tuesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Wednesday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Thursday &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; Friday&lt;/span&gt; with &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;(Monday:Friday)&lt;/span&gt;,
which perform identically. The new approach has the benefit of being shorter,
and of scaling to an arbitrary number of switch fields (we would just need to
replace &lt;span class=&quot;formula decimalpoint&quot;&gt;Friday&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Friday&lt;/span&gt; with the new last field).&lt;/p&gt;

&lt;p&gt;How does it work? You may recall &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;from our November introduction&lt;/a&gt; that
&lt;span class=&quot;formula decimalpoint&quot;&gt;Monday:Friday&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Monday:Friday&lt;/span&gt; is a range, which in this case is a short-hand
for expressing the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ Monday, Tuesday, Wednesday, Thursday, Friday }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Monday; Tuesday; Wednesday; Thursday; Friday }&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;An array is a list of values, known as &lt;em&gt;elements&lt;/em&gt;. The &lt;span class=&quot;link function&quot; name=&quot;OR&quot;&gt;OR&lt;/span&gt;
function returns TRUE only if at least a single element is TRUE. Here, it
returns TRUE only if the user has toggled one or several switch fields to their
“on” positions.&lt;/p&gt;

&lt;p&gt;Now, let’s look at the second parameter to the IF function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;, FALSE, &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Monday:Friday, Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE).&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;; FALSE; &lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Monday:Friday; Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE),&lt;span class=&quot;property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;.&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; takes the array to filter as its first parameter and a
logical array of the same size as its second parameter, which determines which
elements of the first array are returned. If an element of the second array is
TRUE, the corresponding element of the first array is included in the returned
array, otherwise, the element is dropped.&lt;/p&gt;

&lt;p&gt;Here, the array to filter is &lt;span class=&quot;formula decimalpoint&quot;&gt;Monday:Friday&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Monday:Friday&lt;/span&gt; — an array of
switch fields — and the logical array is &lt;span class=&quot;formula decimalpoint&quot;&gt;Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Monday:Friday &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; TRUE&lt;/span&gt;. As you might expect, the logical array consists of five elements — one
for every weekday — and it is TRUE only where the user has toggled the
corresponding switch field to its “on” position. As a result, FILTER returns an
array of switch fields that the user has toggled.&lt;/p&gt;

&lt;p&gt;Before we move on to TEXTJOIN, there’s one final bit of business to discuss.
After &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…)&lt;/span&gt;, the eagle-eyed reader may have
noticed that &lt;span class=&quot;formula decimalpoint&quot;&gt;.Label&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;,Label&lt;/span&gt; has been added:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;FILTER(…).Label&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;FILTER(…),Label&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Recall that FILTER returns an array of switch fields. A switch field supports
various properties, including &lt;span class=&quot;link property&quot; parent-type=&quot;SwitchField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;, which returns
the label of the field. As a result, by appending &lt;span class=&quot;formula decimalpoint&quot;&gt;.Label&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;,Label&lt;/span&gt;, we effectively transform an array of switch fields to an array
of text strings, representing their labels.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt; joins array elements together in a single text string,
separating the elements with the delimiter given as the first parameter. For
instance, &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;x&quot;, FALSE, { &quot;a&quot;, &quot;b&quot;, &quot;c&quot; })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;x&quot;; FALSE; { &quot;a&quot;; &quot;b&quot;; &quot;c&quot; })&lt;/span&gt; returns
“axbxc”.&lt;/p&gt;

&lt;p&gt;Putting it all together, TEXTJOIN takes an array of text strings representing
weekdays and produces a single text string, where every weekday is separated by
a comma and a space.&lt;/p&gt;

&lt;p&gt;Again, the new approach is cleaner, shorter and scales to an arbitrary number of
switch fields. The one downside is that you need to have a better understanding
of how formulas work — but once you do, you will find that you can supercharge
a lot of older formulas, making them more concise, more powerful and easier to
maintain.&lt;/p&gt;

</description>
        <pubDate>Thu, 02 Jun 2022 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2022/06/02/text-summary.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2022/06/02/text-summary.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Display all US legal holidays for a given year</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  In this post, we create an app that displays all legal US holidays for a given
  year. The app adapts a formula created for Microsoft Excel and uses new
  functions introduced with our new formula engine, like FORMATDATE, FILTER and
  TEXTJOIN.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Tip%3A%20Display%20all%20US%20legal%20holidays%20for%20a%20given%20year
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on the demo app below ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Legal holidays are days established by law that are not considered to be working
days. While different countries use different legal holidays, we’ll only
consider legal holidays in the United States for this tip.&lt;/p&gt;

&lt;p&gt;What if you want to display a list of all legal holidays for a given year? That
used to be difficult to do with Calcapp, but with &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;our new formula
engine&lt;/a&gt; and its support for &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt;, this is actually
fairly straight-forward.&lt;/p&gt;

&lt;p&gt;This tip introduces a simple app where the year is entered in the number field
&lt;em&gt;Year&lt;/em&gt; and a list of the legal holidays is presented in the text field
&lt;em&gt;LegalHolidays&lt;/em&gt;. Here’s an embedded version of the app, which you can also
&lt;a href=&quot;https://connect.calcapp.net/?app=cji5v2&quot; target=&quot;connect&quot;&gt;run as a
stand-alone app&lt;/a&gt;:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 320px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=cji5v2&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;If you’re familiar with spreadsheets in general, and Microsoft Excel 2021 in
particular, Calcapp’s formula language should be very easy to pick up. You are
generally able to use Excel resources to learn about solving problems and apply
those solutions in Calcapp.&lt;/p&gt;

&lt;p&gt;For this problem, that’s exactly what we did. We found an article discussing US
public holidays on the website of &lt;a href=&quot;https://www.extendoffice.com/documents/excel/2602-excel-if-date-is-public-holiday.html&quot;&gt;Extend Office&lt;/a&gt;, which
lists not only the public holidays, but also formulas for calculating them for a
given year.&lt;/p&gt;

&lt;p&gt;Some legal holidays fall on particular dates every year, like New Year’s Day
(January 1). Other holidays are trickier, like Labor Day, which falls on the
first Monday in September.&lt;/p&gt;

&lt;p&gt;To calculate the date for Labor Day, we’ll use this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1)), 1, 0, 6, 5, 4, 3, 2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1)); 1; 0; 6; 5; 4; 3; 2)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first part, &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1)&lt;/span&gt;, returns September 1 of the
year indicated by the &lt;em&gt;Year&lt;/em&gt; field. We then add a number of days to that date,
calculated by this part of the formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1)), 1, 0, 6, 5, 4, 3, 2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1)); 1; 0; 6; 5; 4; 3; 2)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt; function returns a number corresponding to the day
of the week for a given date (in this case, September 1). When no second
parameter is given to WEEKDAY, 1 is returned for Sunday, 2 is returned for
Monday, and so on.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; returns the parameter indicated by its first parameter.
&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(2, &quot;one&quot;, &quot;two&quot;, &quot;three&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(2; &quot;one&quot;; &quot;two&quot;; &quot;three&quot;)&lt;/span&gt; returns “two”, because the
first parameter indicates that of the remaining parameters, the second one
should be chosen.&lt;/p&gt;

&lt;p&gt;In the formula above, the value returned from WEEKDAY is fed into CHOOSE. If
September 1 is a Sunday, 1 is added. Why? Because Labor Day always falls on a
Monday. If September 1 is already a Monday, 0 is added, and if September 1 is a
Tuesday, 6 is added, so that the coming Monday is calculated.&lt;/p&gt;

&lt;p&gt;To calculate an array containing the legal holidays of a certain year, we use
this lengthy formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 1, 1), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 1, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 1, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 2, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 2, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 6, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 6, 6)), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 6, 19), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 7, 4), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 10, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 7 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 10, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 11, 11), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 11, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 21 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 11, 1)), 4, 3, 2, 1, 0, 6, 5), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 12, 25) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 1; 1); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 1; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 1; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 2; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 2; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 6; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 6; 6)); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 6; 19); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 7; 4); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 10; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 7 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 10; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 11; 11); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 11; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 21 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 11; 1)); 4; 3; 2; 1; 0; 6; 5); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 12; 25) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula has been adapted from the &lt;a href=&quot;https://www.extendoffice.com/documents/excel/2602-excel-if-date-is-public-holiday.html&quot;&gt;Extend Office
article&lt;/a&gt;, with &lt;a href=&quot;https://en.wikipedia.org/wiki/Juneteenth&quot;&gt;Juneteenth&lt;/a&gt; added (which was
made a federal holiday only last year).&lt;/p&gt;

&lt;p&gt;The formula above includes all dates, regardless of whether they fall on a
Saturday or a Sunday, though. We can easily filter out days that fall on
weekends using &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;There is a version of FILTER that takes an array as its first parameter and a
formula fragment as its second parameter, which we’ll use here. The formula
fragment has access to the element under consideration under the &lt;em&gt;Element&lt;/em&gt; name,
and is expected to return TRUE if the element should be kept and FALSE
otherwise.&lt;/p&gt;

&lt;p&gt;This formula returns the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 3 }&lt;/span&gt;, as only odd elements
are kept:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1, 2, 3 }, &lt;span class=&quot;function&quot; name=&quot;ISODD&quot;&gt;ISODD&lt;/span&gt;(Element))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ 1; 2; 3 }; &lt;span class=&quot;function&quot; name=&quot;ISODD&quot;&gt;ISODD&lt;/span&gt;(Element))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To determine if a date should be kept, we’ll use the WEEKDAY function. When
invoked with 2 as its second parameter, 1 is returned for Monday, 2 is returned
for Tuesday, 5 is returned for Friday, and so on. That means that we can check
the return value to see if it is less than or equal to 5 to filter out dates
that fall on a weekend:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…, &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element, 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…, &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element; 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If we plug in the long array formula fragment with the dates in place of
&lt;code&gt;...&lt;/code&gt;, we finally have our formula!&lt;/p&gt;

&lt;p&gt;Now, we just need to present it in a text field. First, we’ll use the
&lt;span class=&quot;link function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt; function to format all dates of the array as text.
When FORMATDATE is invoked with an array, it is invoked once for every array
element, with the results collected as an array. This formula does what we
need:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…, &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element, 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5), DateFormat.FullDayInWeek)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…, &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element; 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5); DateFormat,FullDayInWeek)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Now, instead of an array containing &lt;span class=&quot;link property&quot; parent-type=&quot;DateTimeField&quot; name=&quot;Value&quot;&gt;sequential serial numbers&lt;/span&gt;, representing dates of legal holidays, we have a text
array containing the formatted versions of these dates. In order to present a
value in a text field, though, we need a plain text string.&lt;/p&gt;

&lt;p&gt;To create said text string, &lt;span class=&quot;link function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt; is used. It takes an array
of text strings and joins all the text strings together in a single text string.
Its third parameter is the array to join together and its first parameter is the
delimiter, separating the elements.&lt;/p&gt;

&lt;p&gt;The delimiter is often set to something like “, “ (which uses a comma to
separate array elements), but here, we want each date to appear on its own line.
(The text field must be configured to display multiple lines by toggling the
&lt;strong&gt;Multiple lines&lt;/strong&gt; property in the inspector when the text field is selected in
Calcapp Creator.)&lt;/p&gt;

&lt;p&gt;To that end, we use the &lt;span class=&quot;link function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt; function in place of the
delimiter, which returns a line break:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;(), FALSE, &lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…,
&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element, 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5), DateFormat.FullDayInWeek))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;(); FALSE; &lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(…,
&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element; 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5); DateFormat,FullDayInWeek))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The last step is to plug in the long array in place of &lt;code&gt;...&lt;/code&gt;. Here is the
complete formula, which returns a text string representing all legal US holidays
of a certain year:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;(), FALSE, &lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 1, 1), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 1, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 1, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 2, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 2, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 6, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 6, 6)), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 6, 19), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 7, 4), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 9, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 10, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 7 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 10, 1)), 1, 0, 6, 5, 4, 3, 2), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 11, 11), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 11, 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 21 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 11, 1)), 4, 3, 2, 1, 0, 6, 5), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year, 12, 25) }, &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element, 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5), DateFormat.FullDayInWeek))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;(); FALSE; &lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 1; 1); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 1; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 1; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 2; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 14 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 2; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 6; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;SUBTRACTION&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 6; 6)); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 6; 19); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 7; 4); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 9; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 10; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 7 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 10; 1)); 1; 0; 6; 5; 4; 3; 2); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 11; 11); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 11; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 21 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 11; 1)); 4; 3; 2; 1; 0; 6; 5); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(Year; 12; 25) }; &lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Element; 2) &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN_OR_EQUAL_TO&quot;&gt;&amp;lt;=&lt;/span&gt; 5); DateFormat,FullDayInWeek))&lt;/span&gt;&lt;/p&gt;

</description>
        <pubDate>Mon, 18 Apr 2022 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2022/04/18/holidays.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2022/04/18/holidays.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Custom formatting of dates</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  When formatting dates, you can choose from five pre-defined date formats. What
  if you want a custom date format? For output fields, you can use text fields
  and formulas to achieve this. This post explores two formula approaches.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Handling dates and times has been a key part of many apps built with Calcapp,
ever since we introduced support &lt;a href=&quot;/blog/2016/05/28/dates.html&quot;&gt;way back in 2016&lt;/a&gt;. Our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;November
release&lt;/a&gt; improved upon this support by making it
possible to format dates and times using formulas with the new functions
&lt;span class=&quot;link function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;FORMATTIME&quot;&gt;FORMATTIME&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;However, one thing has remained the same: you are still limited to the date and
time formats we support. Here they are, along with the names you need to use
with FORMATDATE:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Date format&lt;/th&gt;
      &lt;th&gt;US English example&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;

  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;DateFormat.Month&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Nov 1981&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;DateFormat.Numeric&lt;/code&gt; (default)&lt;/td&gt;
      &lt;td&gt;14/11/81&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;DateFormat.Abbreviated&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Nov 14, 1981&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;DateFormat.Full&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;November 14, 1981&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;&lt;code&gt;DateFormat.FullDayInWeek&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;Saturday, November 14, 1981&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;What if you want something a bit more custom, though? As things stand, the only
way to get the weekday to be part of the formatted value is to use
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateFormat.FullDayInWeek&lt;/code&gt;, but then you also need to accept that the month is
written out in full, which may not be desirable.&lt;/p&gt;

&lt;p&gt;You can customize how dates are formatted using formulas. This currently only
works with output fields (that is, fields which display calculated values, as
opposed to input fields that allow the user to enter data).&lt;/p&gt;

&lt;p&gt;(If you’d like to format the values displayed in input fields using a formula,
we’d love to make that happen. &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;Write us and let us know&lt;/a&gt;, so we can
prioritize this work!)&lt;/p&gt;

&lt;h2 id=&quot;using-choose-weekday-month-day-and-year-to-format-a-date&quot;&gt;Using CHOOSE, WEEKDAY, MONTH, DAY and YEAR to format a date&lt;/h2&gt;

&lt;p&gt;We can use a formula to fully replicate what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DateFormat.FullDayInWeek&lt;/code&gt; does.
Recall that this date format produces the following text:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Saturday, November 14, 1981
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we are looking to produce this text instead:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Saturday, Nov 14, 1981
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s assume that the date to format is contained in a date and time field named
&lt;em&gt;Date&lt;/em&gt;. Let’s also assume that we add a new text field, which will hold a
formatted version of the &lt;em&gt;Date&lt;/em&gt; value, using full weekdays and abbreviated month
names.&lt;/p&gt;

&lt;p&gt;Here’s the full formula, which we’ll dissect in a bit:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Date), &quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt;(Date), &quot;Jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;, &quot;Apr&quot;, &quot;May&quot;, &quot;Jun&quot;, &quot;Jul&quot;, &quot;Aug&quot;, &quot;Sep&quot;, &quot;Oct&quot;, &quot;Nov&quot;, &quot;Dec&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Date); &quot;Sunday&quot;; &quot;Monday&quot;; &quot;Tuesday&quot;; &quot;Wednesday&quot;; &quot;Thursday&quot;; &quot;Friday&quot;; &quot;Saturday&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt;(Date); &quot;Jan&quot;; &quot;Feb&quot;; &quot;Mar&quot;; &quot;Apr&quot;; &quot;May&quot;; &quot;Jun&quot;; &quot;Jul&quot;; &quot;Aug&quot;; &quot;Sep&quot;; &quot;Oct&quot;; &quot;Nov&quot;; &quot;Dec&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above makes heavy use of the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; operator, which joins
text strings together. &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;ab&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;cd&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;ab&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;cd&quot;&lt;/span&gt; returns “abcd”.&lt;/p&gt;

&lt;p&gt;First off, let’s look at how deriving the weekday name from the &lt;em&gt;Date&lt;/em&gt; value
works. Here’s that part of the formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Date), &quot;Sunday&quot;, &quot;Monday&quot;, &quot;Tuesday&quot;, &quot;Wednesday&quot;, &quot;Thursday&quot;, &quot;Friday&quot;, &quot;Saturday&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt;(Date); &quot;Sunday&quot;; &quot;Monday&quot;; &quot;Tuesday&quot;; &quot;Wednesday&quot;; &quot;Thursday&quot;; &quot;Friday&quot;; &quot;Saturday&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;WEEKDAY&quot;&gt;WEEKDAY&lt;/span&gt; returns a number corresponding to the day of the week.
If a second parameter is not given, 1 is returned for Sunday, 2 is returned for
Monday, and so on.&lt;/p&gt;

&lt;p&gt;That’s perfect for the &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; function, which returns the second
parameter if the first parameter is set to 1, the third parameter if the second
parameter is set to 2, etc. &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(2, &quot;one&quot;, &quot;two&quot;, &quot;three&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(2; &quot;one&quot;; &quot;two&quot;; &quot;three&quot;)&lt;/span&gt;
returns “two”. By plugging in the return value from WEEKDAY into CHOOSE, we get
the behavior we’re looking for.&lt;/p&gt;

&lt;p&gt;Next, we join together the weekday with “, “, followed by the abbreviated month
name, using &lt;span class=&quot;link function&quot; name=&quot;MONTH&quot;&gt;MONTH&lt;/span&gt; to extract a number corresponding with the
month of the &lt;em&gt;Date&lt;/em&gt; field, starting with 1. We then join together that text
string with “ “ and &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DAY&quot;&gt;DAY&lt;/span&gt;(Date)&lt;/span&gt;, which creates a space between
the abbreviated month name and the day of the month.&lt;/p&gt;

&lt;p&gt;Finally, we join together the text string with “, “ and &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;YEAR&quot;&gt;YEAR&lt;/span&gt;(Date)&lt;/span&gt;, which adds the year after a comma and a space. Now we’re done!&lt;/p&gt;

&lt;h2 id=&quot;using-regular-expressions-to-format-a-date-advanced&quot;&gt;Using regular expressions to format a date (advanced)&lt;/h2&gt;

&lt;p&gt;The solution above successfully formats a date using full weekdays and
abbreviated month names. To do so, however, it essentially reinvents what the
&lt;span class=&quot;link function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt; function does. What if we could take the output
generated by that function and alter the month name, removing everything that
follows its first three letters (so that “January” becomes “Jan”)?&lt;/p&gt;

&lt;p&gt;We can, and there are multiple ways to do it. You could use the text processing
functions Calcapp has inherited from spreadsheets, functions like
&lt;span class=&quot;link function&quot; name=&quot;FIND&quot;&gt;FIND&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;MID&quot;&gt;MID&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;LEFT&quot;&gt;LEFT&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;RIGHT&quot;&gt;RIGHT&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;However, &lt;em&gt;regular expressions&lt;/em&gt; are much more powerful than the old text
processing functions, though there is a learning curve. When Calcapp gained
support for regular expressions in 2018, we wrote &lt;a href=&quot;/blog/2018/04/06/regular-expressions.html&quot;&gt;a lengthy
introduction&lt;/a&gt;, which we invite you to read.&lt;/p&gt;

&lt;p&gt;Feel free to ignore this section if you like – using CHOOSE, WEEKDAY, MONTH,
DAY and YEAR to format a date works perfectly well, and is much easier to
understand.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;REGEXREPLACE&quot;&gt;REGEXREPLACE&lt;/span&gt; matches a text string against a regular expression,
where the text string is given as the first parameter and the regular expression
is given as the second parameter. The replacement text string is given as the
third parameter.&lt;/p&gt;

&lt;p&gt;This formula removes all numbers from a text string, returning “abc”:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXREPLACE&quot;&gt;REGEXREPLACE&lt;/span&gt;(&quot;a1b2c3&quot;, &quot;\d&quot;, &quot;&quot;, TRUE)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXREPLACE&quot;&gt;REGEXREPLACE&lt;/span&gt;(&quot;a1b2c3&quot;; &quot;\d&quot;; &quot;&quot;; TRUE)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The second parameter, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d&lt;/code&gt; is the regular expression, which matches a single
number (&lt;em&gt;d&lt;/em&gt; stands for &lt;em&gt;digit&lt;/em&gt;). The third parameter ensures that all those
numbers are replaced with the empty text string, effectively meaning that they
are removed. The fourth parameter, TRUE, ensures that all numbers are replaced,
not just the first one.&lt;/p&gt;

&lt;p&gt;Here’s a formula which takes the FORMATDATE output and shortens the month name:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXREPLACE&quot;&gt;REGEXREPLACE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(Date, DateFormat.FullDayInWeek), &quot;^([^,]+, \w\w\w)[^\d]&lt;em&gt;(.&lt;/em&gt;)$&quot;, &quot;$1 $2&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXREPLACE&quot;&gt;REGEXREPLACE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(Date; DateFormat,FullDayInWeek); &quot;^([^,]+, \w\w\w)[^\d]&lt;em&gt;(.&lt;/em&gt;)$&quot;; &quot;$1 $2&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Refer to our &lt;a href=&quot;/blog/2018/04/06/regular-expressions.html&quot;&gt;full primer on regular expressions&lt;/a&gt; to truly understand the
regular expression above.&lt;/p&gt;

&lt;p&gt;The first part, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^([^,]+, \w\w\w)&lt;/code&gt;, uses a &lt;em&gt;capturing group&lt;/em&gt; to capture the
weekday and the first three letters of the month name. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^&lt;/code&gt; matches the beginning
of the text string. The parentheses capture the entire contents as the first
capturing group. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[^,]+&lt;/code&gt; means “capture everything up until the first comma.”
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;, \w\w\w&lt;/code&gt; means “capture the first three letters that follow a comma and a
space.”&lt;/p&gt;

&lt;p&gt;The final part, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[^\d]*(.*)$&lt;/code&gt; captures the rest of the text string. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[^\d]*&lt;/code&gt;
means “capture everything up until the first number” (representing the day). It
is not part of a capturing group (there are no parentheses) – as we shall soon
see, that essentially means that we throw it away. Finally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(.*)$&lt;/code&gt; means
“capture everything that remains, up until the end”. There are parentheses,
meaning that “everything that remains” is captured as the second capturing
group.&lt;/p&gt;

&lt;p&gt;The third parameter to REGEXREPLACE is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1 $2&lt;/code&gt;. This means that the
resulting text string is composed of the contents of the first capturing group,
represented by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt; (containing the weekday and the first three letters of the
month name), followed by a space, followed by the contents of the second
capturing group, represented by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$2&lt;/code&gt; (containing the day and the year).&lt;/p&gt;

&lt;p&gt;Depending on your perspective, this may seem like a much more difficult way to
format the date than simply joining a few text strings together. Use whichever
method you prefer.&lt;/p&gt;

</description>
        <pubDate>Tue, 01 Mar 2022 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2022/03/01/date-formatting.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2022/03/01/date-formatting.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Add separators to reports</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Add separators between fields — essentially, line breaks — anywhere you like
  in your reports by following the steps of this tip.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;big release in November&lt;/a&gt; improved many long-standing
requests related to reports. It enabled you to &lt;a href=&quot;/blog/2021/11/12/formula-driven-emails.html&quot;&gt;send formula-driven
emails&lt;/a&gt;, &lt;a href=&quot;/blog/2021/11/12/reports.html&quot;&gt;use a formula to determine what fields to
include in a report&lt;/a&gt; and added many &lt;a href=&quot;/blog/2021/11/12/csv.html&quot;&gt;new options&lt;/a&gt; for reports
using comma-separated (CSV) or tab-separated (TSV) values.&lt;/p&gt;

&lt;p&gt;However, a fair number of long-standing feature requests have not yet been
addressed. The biggest is likely the PDF report designer &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html#other-changes&quot;&gt;we have promised for
an embarrassingly long time now&lt;/a&gt;. While we have
nothing new to announce regarding the PDF report designer, there are compelling
third-party alternatives that can easily be used with Calcapp, &lt;a href=&quot;/blog/2020/08/17/zapier-pdf.html&quot;&gt;as detailed by
this blog post from 2020&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another feature our customers have requested for years concerns the ability to
add separators to reports, that is, line breaks between groups of fields. PDF
reports automatically separate different screens (optionally with headings for
each and every screen), but sometimes it’s desirable to have line breaks without
having to create a new screen.&lt;/p&gt;

&lt;p&gt;We recently made some minor changes which enable this exact functionality,
meaning that you can now introduce line breaks wherever you like by following
these steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Add a new text field. Select &lt;strong&gt;abc&lt;/strong&gt; from the inspector after you have
pressed &lt;strong&gt;Add field&lt;/strong&gt; (which creates a number field).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Make the field invisible by toggling the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;
property in the inspector, so that the separator does not show up in the user
interface of your app.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Assign the field a label equal to a single space character. If the field is
the second separator of the screen, use two space characters, and so on. This
is important, as you otherwise get unsightly “ (2)”, “ (3)” labels in your
report (which normally serve to differentiate fields with identical labels,
but here they need to be suppressed by using ostensibly different labels).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Assign the formula &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot; &quot;&lt;/span&gt; to the separator fields.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add a new report button, by pressing &lt;strong&gt;Add button&lt;/strong&gt; and then selecting
something like &lt;strong&gt;Open report&lt;/strong&gt; from the drop-down in the inspector that
initially reads &lt;strong&gt;Reset field&lt;/strong&gt;. You need to include invisible fields by
toggling the &lt;strong&gt;Include hidden fields&lt;/strong&gt; property, so that the separator fields
are included.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The steps above have the effect of adding fields with labels and values which
are only made up of invisible space characters. This isn’t particularly elegant,
but it works.&lt;/p&gt;

&lt;p&gt;We are aware that many customers expect reports to include everything in a
screen, including text boxes, buttons and field group separators (which would
have made this tip superfluous). This is something that we will realize in a
future release.&lt;/p&gt;

&lt;p&gt;For now, though, this tip enables you to add field separators to reports
anywhere you like.&lt;/p&gt;

</description>
        <pubDate>Mon, 10 Jan 2022 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2022/01/10/report-separators.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2022/01/10/report-separators.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Release: Our November, 2021 update is here</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our biggest release ever is here, celebrated with 23 blog posts. Use 100+ new
  functions, including XLOOKUP and SUMIFS. Determine the next screen and what
  fields are included in a report using formulas. Several thousand formula
  examples help you get started with all the new features.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;


&lt;a href=&quot;/assets/media/blog/2021-11-12-release/wallpaper-5k.jpg&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2021-11-12-release/hero.jpg&quot;
       alt=&quot;An image commemorating the release&quot;
       class=&quot;large-image no-shadow&quot;&gt;&lt;/a&gt;

&lt;h2&gt;What&apos;s new?&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;A new formula engine — and a note from our co-founder.&lt;/strong&gt;
    Two years in the making, our new formula engine is finally ready. It powers
    more than 100 new functions, operators and properties, making more types of
    apps possible than ever before.
    &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;100+ new functions.&lt;/strong&gt;
    We now support 102 new functions, including Excel 2021 marvels like XLOOKUP
    and FILTER, spreadsheet classics like SUMIF, COUNTIFS, INDEX and MATCH as
    well as the power user favorites MAP and REDUCE.
    &lt;a href=&quot;/blog/2021/11/12/new-functions.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Arrays and ranges.&lt;/strong&gt;
    Calcapp now supports arrays and ranges. Arrays are collections of values
    which enable many of our new functions and properties. A range is a
    short-hand for constructing arrays with many elements. (Need to sum 100
    fields? Easy!)
    &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Look up values with XLOOKUP.&lt;/strong&gt;
    Excel 2021&apos;s XLOOKUP function is now fully supported. It does everything
    VLOOKUP and HLOOKUP do and more. Use an app to convert table data to XLOOKUP
    formulas.
    &lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Use SUMIF, SUMIFS and others like them.&lt;/strong&gt;
    AVERAGEIF, COUNTIF, MINIFS, MAXIFS, PRODUCTIF, SUMIF and variants are now
    supported. Use our formula fragment extension for complex conditions.
    &lt;a href=&quot;/blog/2021/11/12/conditional-functions.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Send formula-driven emails.&lt;/strong&gt;
    Fully determine the bodies of emails you send using formulas. You can also
    use formulas to set text that appears before or after field values in
    reports.
    &lt;a href=&quot;/blog/2021/11/12/formula-driven-emails.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Use a formula to determine what fields to include in a
    report.&lt;/strong&gt;
    Gain full flexibility using our new functions. Want to only include fields
    with values greater than five? Just use FILTER. Also, hidden fields can now
    be left out of reports.
    &lt;a href=&quot;/blog/2021/11/12/reports.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Decide the next screen with a formula.&lt;/strong&gt;
    Skip straight to the results if the entered data checks out, or collect
    supplemental information otherwise. Stop copying and pasting screens — now
    you can make many screens send the user to the same destination.
    &lt;a href=&quot;/blog/2021/11/12/next-screen.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Decimal commas in formulas.&lt;/strong&gt;
    Formulas written with decimal commas are now fully supported. Set your
    preference the next time you open Calcapp Creator.
    &lt;a href=&quot;/blog/2021/11/12/decimal-separator.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Dramatically improved documentation for formulas and
    properties.&lt;/strong&gt;
    What&apos;s got half a million words? The Lord of the Rings trilogy. And our new
    formula and property documentation, which is now on the web. Thousands of
    formula examples make getting started with all the new features easy.
    &lt;a href=&quot;/blog/2021/11/12/documentation.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;IF without all the parentheses, SWITCH and IFBLANK.&lt;/strong&gt;
    Use the IF function with multiple conditions without having to use more than
    two parentheses. Use SWITCH when you need to test the same value for
    equality against other values.
    &lt;a href=&quot;/blog/2021/11/12/if-switch-ifblank.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;More options for CSV and TSV files.&lt;/strong&gt;
    CSV files produced by report buttons can now be customized to make them
    compatible with more apps and services. Change the decimal separator and the
    delimiter separating values and lay out values vertically instead of
    horizontally.
    &lt;a href=&quot;/blog/2021/11/12/csv.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;More customizable reset buttons.&lt;/strong&gt;
    Use a formula to determine what fields are reset by a reset button. These
    buttons can now assign blank values to fields.
    &lt;a href=&quot;/blog/2021/11/12/reset-buttons.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Download and start large apps faster.&lt;/strong&gt;
    Many under-the-hood improvements make large apps download and start faster
    and consume less space when stored for offline use.
    &lt;a href=&quot;/blog/2021/11/12/large-apps.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Include array elements conditionally with IF.&lt;/strong&gt;
    Use IF to determine if an element should be part of an array.
    &lt;a href=&quot;/blog/2021/11/12/array-if.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Join arrays together with |.&lt;/strong&gt;
    Use the new operator | to join together arrays with other arrays and values.
    &lt;a href=&quot;/blog/2021/11/12/array-concatenation.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;No more typos when referencing colors.&lt;/strong&gt;
    Colors can now be referenced with no risk of typos, thanks to &quot;enums.&quot;
    XLOOKUP, XMATCH and FORMATDATE also support enums, which help warn you of
    errors early.
    &lt;a href=&quot;/blog/2021/11/12/enums.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Tips for getting the most out of Calcapp&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Debug arrays by inspecting their elements.&lt;/strong&gt;
    If a function isn&apos;t returning the value you expect, you need to look at the
    parameters it receives by creating new temporary fields visualizing the
    parameters. To do so with an array, you need to convert it to a text string
    first using the TEXTJOIN function.
    &lt;a href=&quot;/blog/2021/11/12/debug-arrays.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Avoid gotchas when adding text boxes and buttons in the middle of a
    range.&lt;/strong&gt;
    Ranges are an effective means of creating arrays containing many elements.
    However, it is easy to lose track of what elements they contain, which can
    have surprising results. This tip explores this topic in depth.
    &lt;a href=&quot;/blog/2021/11/12/range-gotcha.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;More news&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Panels are now known as screens — and other name changes.&lt;/strong&gt;
    Panels have been renamed to screens to better reflect the expectations of
    app authors. There are other name changes, which better reflect how Calcapp
    is used today and how we expect it to be used tomorrow.
    &lt;a href=&quot;/blog/2021/11/12/new-names.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Backward compatibility and our new formula engine.&lt;/strong&gt;
    We work hard to ensure that your apps continue working, even as we add
    features to Calcapp. With our new formula engine, we have made some minor
    changes, but they should not affect your existing apps.
    &lt;a href=&quot;/blog/2021/11/12/backward-compatibility.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Sample app: Convert spreadsheet tables to XLOOKUP formulas.&lt;/strong&gt;
    Our latest sample app converts spreadsheet column data to formulas that use
    the XLOOKUP function. This post explains in detail how it was built.
    &lt;a href=&quot;/blog/2021/11/12/xlookup-generator.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 12 Nov 2021 22:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/release.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/release.html</guid>
        
        <category>Release</category>
        
        
      </item>
    
      <item>
        <title>Feature: A new formula engine — and a note from our co-founder</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  After two years, our new formula engine is finally ready. It powers more than
  100 new functions, operators and properties, making more types of apps
  possible than ever before.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our new formula engine adds new features that allow us to support &lt;a href=&quot;/blog/2021/11/12/new-functions.html&quot;&gt;more than 100
new functions&lt;/a&gt; and enables us to make the existing functions more
flexible. The revamped &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; function accepts multiple conditions
without any extra parentheses and the new &lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt; function
enables concise conditions to be expressed. &lt;a href=&quot;/blog/2021/11/12/if-switch-ifblank.html&quot;&gt;Learn more »&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;Arrays&lt;/a&gt; enable a large number of new functions, like popular
conditional functions like &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt;.
These two functions make it easy to return a sum consisting of only numbers
that match one or more conditions. Other conditional functions return
averages, products and counts. &lt;a href=&quot;/blog/2021/11/12/conditional-functions.html&quot;&gt;Learn more »&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also have support for the full set of new “dynamic array” functions
introduced with Microsoft Excel 2021, including &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;SORT&quot;&gt;SORT&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;SORTBY&quot;&gt;SORTBY&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;. The
jewel in the crown is &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; (along with &lt;span class=&quot;link function&quot; name=&quot;MATCH&quot;&gt;MATCH&lt;/span&gt;
and &lt;span class=&quot;link function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;), which enables true look-ups. As data still needs to
be part of formulas, we have written an app — in Calcapp — that does the
conversion for you. &lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;Learn more »&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a lot of other great new additions to the function library (whose
&lt;a href=&quot;/blog/2021/11/12/documentation.html&quot;&gt;documentation has been dramatically expanded&lt;/a&gt;). There are many
new math, financial and statistical functions — most enabled by the engine’s
array support — convenient new text functions like &lt;span class=&quot;link function&quot; name=&quot;ISEMAIL&quot;&gt;ISEMAIL&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;, and advanced new functions like &lt;span class=&quot;link function&quot; name=&quot;MAP&quot;&gt;MAP&lt;/span&gt;
and &lt;span class=&quot;link function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt;, which borrow from the playbook of traditional
programming. &lt;a href=&quot;/blog/2021/11/12/new-functions.html&quot;&gt;Read the entire list »&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are also new properties which would not have been possible without the new
engine. &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;NextScreen&lt;/span&gt; may be used to determine what
screen the user is brought to using a formula. You can make apps dramatically
smaller — and therefore easier to maintain — by having multiple screens and list
screen navigators bring the user to the same screen. &lt;a href=&quot;/blog/2021/11/12/next-screen.html&quot;&gt;Learn more »&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is now finally possible to determine what
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;fields are included&lt;/span&gt; in a report
using a formula. There are also countless new report features, including
&lt;a href=&quot;/blog/2021/11/12/csv.html&quot;&gt;much-improved support for exporting data to comma-separated values&lt;/a&gt;.
&lt;a href=&quot;/blog/2021/11/12/reports.html&quot;&gt;Learn more »&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Speaking of reports, you can now determine the
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;entire body of an email&lt;/span&gt; solely using
formulas, complete with separate paragraphs. You can also add text before or
after field values — or omit them altogether.
&lt;a href=&quot;/blog/2021/11/12/formula-driven-emails.html&quot;&gt;Learn more »&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This list just scratches the surface of this release. Be sure to read the
&lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;complete release notes&lt;/a&gt; to learn more!&lt;/p&gt;

&lt;h2 id=&quot;a-note-from-our-co-founder&quot;&gt;A note from our co-founder&lt;/h2&gt;

&lt;p&gt;I never thought it would take two years, but it did. Completing a new formula
engine for Calcapp has been the largest, most ambitious undertaking we have
attempted in the history of the project.&lt;/p&gt;

&lt;p&gt;The new engine brings tangible benefits to Calcapp today. You get more than 100
new functions and useful new properties greatly expanding what you can do with
the platform — as well as much-improved documentation — which we discuss above.&lt;/p&gt;

&lt;p&gt;From a cost-benefit perspective, though, spending two years on a new formula
engine may seem like a strange choice. In the short term, we could probably have
gotten more bang for our buck by focusing on other worthy areas.&lt;/p&gt;

&lt;p&gt;After all, there is no shortage of features we could work on. Native apps. More
customizable user interfaces. Data tables – obviating the need to shoe-horn data
into formulas. App store support. If you were mostly fine with our previous
formula support, it is understandable if you are puzzled by this decision to
prioritize the formula engine above so many other useful additions.&lt;/p&gt;

&lt;p&gt;The short answer is that we chose to work on the formula engine because we felt
that it was in the best long-term interests of the project. We have a vision of
where we want to take Calcapp in the future, and many of these features depend
on the new abilities of the formula engine. Without it, our vision could not be
fully realized.&lt;/p&gt;

&lt;p&gt;Also, I’m convinced that an app builder such as Calcapp must have a robust
formula language at its core in order to be useful. There are few other vendors
in this space who share this conviction or who are prepared to make the same
kind of investment that we are. I believe that this focus sets us apart from the
competition and that it will pay dividends well into the future.&lt;/p&gt;

&lt;p&gt;That future isn’t far-off. Soon, we will leverage the new engine to bring you
action formulas. When a button is pressed, you will be able to write a formula
that determines what actions to take, using brand-new action functions. This
feature will make your apps far more dynamic and better able to react to the
data entered by your users, and it wouldn’t have been possible without the new
formula engine.&lt;/p&gt;

&lt;p&gt;On another note, it has almost been six years since we &lt;a href=&quot;/blog/2015/12/10/status.html&quot;&gt;released the first
Calcapp beta&lt;/a&gt; and two and a half years since we &lt;a href=&quot;/blog/2019/04/12/release.html&quot;&gt;ended the
beta and introduced paid plans&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Calcapp did not find its audience immediately. It took several years’ worth of
&lt;a href=&quot;/blog/tag/release.html&quot;&gt;effort&lt;/a&gt; for us to deliver a compelling product, one that people
were willing to stick around for.&lt;/p&gt;

&lt;p&gt;Once we had that product, and once we took the plunge and commercialized
Calcapp, we were rewarded with customers who stick around for the long term. It
is thanks to that financial stability that we can devote several years of effort
to working on an ambitious project such as the formula engine.&lt;/p&gt;

&lt;p&gt;If you’re a customer, thank you. Your support enables us to keep working on
realizing that vision I formulated years ago, when my father (and co-founder)
needed a &lt;a href=&quot;/blog/2018/04/09/launching-after-15-years.html&quot;&gt;life-saving app for his hospital department&lt;/a&gt;
and there were no real options for him in the market.&lt;/p&gt;

&lt;p&gt;He was fortunate to have a programmer for a son who could realize his vision.
Not everyone is so lucky, but now that Calcapp and the larger no-code ecosystem
exist, you don’t need to be.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;David Polberger&lt;br /&gt;
Co-founder, Calcapp&lt;/em&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 21:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/formula-engine.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/formula-engine.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: 100+ new functions</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We now support 102 new functions, including Excel 2021 marvels like XLOOKUP
  and FILTER, spreadsheet classics like SUMIF, COUNTIFS, INDEX and MATCH as well
  as the power user favorites MAP and REDUCE.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Thanks to &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;our new formula engine&lt;/a&gt;, we have been able to add
support for 102 new functions and a few new operators to &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;this
release&lt;/a&gt;, for a grand total of 387 functions.&lt;/p&gt;

&lt;p&gt;Many of the functions are new — either Calcapp exclusives, like
&lt;span class=&quot;link function&quot; name=&quot;ISEMAIL&quot;&gt;ISEMAIL&lt;/span&gt;, or transplants from Microsoft Excel 2021,
like &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; — while many others are classic functions
found in most spreadsheets.&lt;/p&gt;

&lt;p&gt;Calcapp went from supporting 20 functions to 244 functions &lt;a href=&quot;/blog/2016/05/25/244-functions.html&quot;&gt;overnight in
2016&lt;/a&gt;. At that time, we didn’t have support for arrays. As
a result, we couldn’t add functions like &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;FVSCHEDULE&quot;&gt;FVSCHEDULE&lt;/span&gt;, as there was no way to express these functions
without arrays. We’re thrilled to finally be able to bring you these classic
functions.&lt;/p&gt;

&lt;p&gt;We haven’t been content to just bring Calcapp up to speed with the older
versions of Excel, we have added support for &lt;a href=&quot;https://exceljet.net/dynamic-array-formulas-in-excel&quot;&gt;all eight dynamic array
functions&lt;/a&gt; introduced with Excel 2021 (and Microsoft
365 before that): &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;RANDARRAY&quot;&gt;RANDARRAY&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;SEQUENCE&quot;&gt;SEQUENCE&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;SORT&quot;&gt;SORT&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;SORTBY&quot;&gt;SORTBY&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;UNIQUE&quot;&gt;UNIQUE&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Many of the new functions come with Calcapp extensions. &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; and all conditional functions (&lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt; and others) all use some kind of a condition parameter to
determine which element or elements to select. Traditionally, this is done by
providing either &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;a single value the function should look for&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;a text string specifying a condition&lt;/span&gt; or
&lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;a logical array determining which elements to keep&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Calcapp gives you a choice of doing it the traditional way, or using formula
fragments, which makes functions like SUMIF considerably more powerful. A
formula fragment has access to the full power of the formula language (including
the ability to reference values everywhere in the app and the ability to invoke
arbitrary functions). Check out the links above to learn more.&lt;/p&gt;

&lt;p&gt;(If you have been exposed to a traditional programming language like JavaScript,
you may be interested to know that a &lt;em&gt;formula fragment&lt;/em&gt; is our name for an
&lt;em&gt;anonymous function&lt;/em&gt;, or a &lt;em&gt;lambda&lt;/em&gt;. We think that our name is easier to
understand for people used to spreadsheets.)&lt;/p&gt;

&lt;p&gt;Last but not least, all functions and operators now come with detailed
documentation, with thousands of examples tailored for Calcapp and app creation.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/if-switch-ifblank.html&quot;&gt;Feature: IF without all the parentheses, SWITCH and
IFBLANK&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;Feature: Look up values with XLOOKUP, MATCH and INDEX&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/conditional-functions.html&quot;&gt;Feature: Support for SUMIF, SUMIFS and other conditional
functions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/array-concatenation.html&quot;&gt;Feature: Use | to join arrays together with other arrays and
values&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/array-if.html&quot;&gt;Feature: Use IF to conditionally include array elements&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/documentation.html&quot;&gt;Feature: Dramatically improved documentation for formulas and
properties, with thousands of examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;new-date-and-time-functions&quot;&gt;New date and time functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/isoweeknum.html&quot;&gt;ISOWEEKNUM&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the ISO week number of the given date, from 1 through 54.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/networkdays.html&quot;&gt;NETWORKDAYS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of working days between two dates.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/workday.intl.html&quot;&gt;WORKDAY.INTL&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns a date advanced or set back a number of working days.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-financial-functions&quot;&gt;New financial functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/fvschedule.html&quot;&gt;FVSCHEDULE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the future value of a lump sum, with changing future interest
        rates.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/irr.html&quot;&gt;IRR&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Calculates the internal rate of return of a series of cash flows.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/mirr.html&quot;&gt;MIRR&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the modified internal rate of return of a series of cash flows.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/xirr.html&quot;&gt;XIRR&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Calculates the internal rate of return of a series of irregular cash
        flows.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/xnpv.html&quot;&gt;XNPV&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the net present value of an investment with irregular cash
        payments.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-information-functions&quot;&gt;New information functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/size.html&quot;&gt;SIZE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the size of the given array, that is, the number of elements
        that are contained in the array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/tocolor.html&quot;&gt;TOCOLOR&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the given value converted to a color.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/type.html&quot;&gt;TYPE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the type of the given value.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-logical-functions&quot;&gt;New logical functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/ifblank.html&quot;&gt;IFBLANK&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns a value unchanged if it is not blank and a different value
        otherwise.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/ifs.html&quot;&gt;IFS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns one of the given values based on logical conditions.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/switch.html&quot;&gt;SWITCH&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Tests a given parameter for equality against a list of parameters and
        returns a parameter associated with the parameter which matched the
        first parameter.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-lookup-functions&quot;&gt;New lookup functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/filter.html&quot;&gt;FILTER&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Filters the first array using the second parameter.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/index-function.html&quot;&gt;INDEX&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the array element at the given position.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/map.html&quot;&gt;MAP&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Applies the transformation specified by the given formula fragment to
        all array elements and returns the resulting array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/match.html&quot;&gt;MATCH&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the position that a given value appears at in the given lookup
        array, or returns an #N/A error if the value cannot be found.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/reduce.html&quot;&gt;REDUCE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Reduces an array of values to a single value using a user-supplied
        formula.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/reversearray.html&quot;&gt;REVERSEARRAY&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Reverses the given array and returns it.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sort.html&quot;&gt;SORT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Sorts and returns the given array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sortby.html&quot;&gt;SORTBY&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Sorts and returns a given array, where the sort order is based on sort
        arrays given to this function.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/unique.html&quot;&gt;UNIQUE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns a version of the given array with all duplicate values removed.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/xlookup.html&quot;&gt;XLOOKUP&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the array element in the second array with the same position as
        an element in the first array which is equal to a given value.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/xmatch.html&quot;&gt;XMATCH&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the position that a given value appears at in the given lookup
        array, or returns an #N/A error if the value cannot be found.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-math-functions&quot;&gt;New math functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/mdeterm.html&quot;&gt;MDETERM&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the matrix determinant of the given matrix.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/minverse.html&quot;&gt;MINVERSE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the inverse matrix of the given matrix.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/mmult.html&quot;&gt;MMULT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the matrix product of the given matrices.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/munit.html&quot;&gt;MUNIT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the unit matrix for the given dimension.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/productif.html&quot;&gt;PRODUCTIF&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the product of the array elements that satisfy a condition
        (multiplying them together).
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/productifs.html&quot;&gt;PRODUCTIFS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the product of all array elements which satisfy one or several
        conditions (multiplying them together).
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/randarray.html&quot;&gt;RANDARRAY&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns an array with random numbers.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sequence.html&quot;&gt;SEQUENCE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns an array containing a sequence of numbers.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sumif.html&quot;&gt;SUMIF&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sum of the array elements that satisfy a condition (adding
        them together).
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sumifs.html&quot;&gt;SUMIFS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sum of all array elements which satisfy one or several
        conditions (adding them together).
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sumproduct.html&quot;&gt;SUMPRODUCT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Multiplies all the given arrays together and returns the sum of
        products.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sumx2my2.html&quot;&gt;SUMX2MY2&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sum of the differences between the corresponding squared
        elements of the given two arrays.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sumx2py2.html&quot;&gt;SUMX2PY2&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sum of the squares of all elements of the given two arrays.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/sumxmy2.html&quot;&gt;SUMXMY2&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sum of the squared differences between the corresponding
        elements of the given two arrays.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-operators&quot;&gt;New operators&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/array-concatenation.html&quot;&gt;&lt;span class=&quot;symbol&quot;&gt;|&lt;/span&gt; Array concatenation&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Joins together two arrays, or joins a value to an array, and returns
        the result.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/double-negation.html&quot;&gt;&lt;span class=&quot;symbol&quot;&gt;--&lt;/span&gt; Double negation&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns 0 if the given operand is FALSE, 1 if it is TRUE and the
        operand unchanged if is a number.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/simple-equality.html&quot;&gt;&lt;span class=&quot;symbol&quot;&gt;==&lt;/span&gt; Simple equality&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns whether the first value is equal to the second value.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/simple-inequality.html&quot;&gt;&lt;span class=&quot;symbol&quot;&gt;!=&lt;/span&gt; Simple inequality&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns whether the first value is not equal to the second value.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-statistical-functions&quot;&gt;New statistical functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/averagea.html&quot;&gt;AVERAGEA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the average (arithmetic mean) of the parameters.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/averageif.html&quot;&gt;AVERAGEIF&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the average (arithmetic mean) of the array elements that
        satisfy a condition.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/averageifs.html&quot;&gt;AVERAGEIFS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the average (arithmetic mean) of all array elements which
        satisfy one or several conditions.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/correl.html&quot;&gt;CORREL&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the Pearson correlation coefficient of two sets of data.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/count.html&quot;&gt;COUNT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of values which can be interpreted as numbers.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/counta.html&quot;&gt;COUNTA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of values which are not blank.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/countblank.html&quot;&gt;COUNTBLANK&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of elements of the given array which are either
        blank or are equal to the empty text string.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/countif.html&quot;&gt;COUNTIF&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of array elements which satisfy a condition.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/countifs.html&quot;&gt;COUNTIFS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of array elements which satisfy one or several
        conditions.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/covariance.p.html&quot;&gt;COVARIANCE.P&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the population covariance, that is, the covariance of the
        product of paired deviations, for an entire population.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/covariance.s.html&quot;&gt;COVARIANCE.S&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sample covariance, that is, the covariance of the product
        of paired deviations, for a sample of the population.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/forecast.html&quot;&gt;FORECAST&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Fits a straight line to data using linear regression and returns the
        vertical coordinate of a point on that line.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/frequency.html&quot;&gt;FREQUENCY&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the frequency distribution of the values of the first array
        when grouped into the intervals of the second array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/growth.html&quot;&gt;GROWTH&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the points of an exponential curve of the form y = b * m ^ x
        through the given data points using linear regression.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/intercept.html&quot;&gt;INTERCEPT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Fits a straight line to data using linear regression and returns its
        intercept on the vertical axis.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/large.html&quot;&gt;LARGE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the nth largest number in the given array, where n is given as
        the second parameter.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/linest.html&quot;&gt;LINEST&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Finds a straight line, y = m * x + b, that best fits the given data,
        and returns an array containing two values corresponding to m and b in
        the equation above.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/maxa.html&quot;&gt;MAXA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the largest number of the given numbers.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/maxifs.html&quot;&gt;MAXIFS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the largest number of all array elements which satisfy one or
        several conditions.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/mina.html&quot;&gt;MINA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the smallest number of the given numbers.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/minifs.html&quot;&gt;MINIFS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the smallest number of all array elements which satisfy one or
        several conditions.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/mode.mult.html&quot;&gt;MODE.MULT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the values that appear most frequently.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/mode.sngl.html&quot;&gt;MODE.SNGL&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the value that appears most frequently.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/pearson.html&quot;&gt;PEARSON&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the Pearson correlation coefficient of two sets of data.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/percentile.exc.html&quot;&gt;PERCENTILE.EXC&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of the given array at the kth percentile, where k is
        a number between 0 and 1 (exclusive), which can also be specified with
        the % operator (.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/percentile.inc.html&quot;&gt;PERCENTILE.INC&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of the given array at the kth percentile, where k is
        a number between 0 and 1 (inclusive), which can also be specified with
        the % operator (.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/percentrank.exc.html&quot;&gt;PERCENTRANK.EXC&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the percentile rank of a number in an array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/percentrank.inc.html&quot;&gt;PERCENTRANK.INC&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the percentile rank of a number in an array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/prob.html&quot;&gt;PROB&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the probability that a value is inside a given interval.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/quartile.exc.html&quot;&gt;QUARTILE.EXC&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of the given array at the given quartile value.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/quartile.inc.html&quot;&gt;QUARTILE.INC&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the number of the given array at the given quartile value.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/rank.avg.html&quot;&gt;RANK.AVG&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the rank of the given number in the given number array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/rank.eq.html&quot;&gt;RANK.EQ&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the rank of the given number in the given number array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/rsq.html&quot;&gt;RSQ&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the square of the Pearson correlation coefficient of two sets
        of data.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/seriessum.html&quot;&gt;SERIESSUM&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sum of the first terms of a power series.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/slope.html&quot;&gt;SLOPE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Fits a straight line to data using linear regression and returns its
        slope.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/small.html&quot;&gt;SMALL&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the nth smallest number in the given array, where n is given as
        the second parameter.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/stdeva.html&quot;&gt;STDEVA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sample standard deviation of the parameters.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/stdevpa.html&quot;&gt;STDEVPA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the population standard deviation of the parameters.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/steyx.html&quot;&gt;STEYX&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Fits a straight line to data using linear regression and returns the
        standard error of the actual vertical coordinates compared to the
        vertical coordinates of the straight line.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/trimmean.html&quot;&gt;TRIMMEAN&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the mean (average) of the given values, ignoring a percentage
        of array elements at the beginning and end of the given array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/vara.html&quot;&gt;VARA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the sample variance of the parameters.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/varpa.html&quot;&gt;VARPA&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the population variance of the parameters.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/z.test.html&quot;&gt;Z.TEST&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the one-tailed cumulative probability value of a Z-test.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;new-text-functions&quot;&gt;New text functions&lt;/h2&gt;

&lt;table class=&quot;section-items&quot;&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/charat.html&quot;&gt;CHARAT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns the character at the given position.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/concat.html&quot;&gt;CONCAT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Joins any number of values together as a single text string and returns
        it.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/contains.html&quot;&gt;CONTAINS&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns whether a text string contains another text string.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/endswith.html&quot;&gt;ENDSWITH&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns whether a text string ends with another text string.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/formatdate.html&quot;&gt;FORMATDATE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns a date as text.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/formattime.html&quot;&gt;FORMATTIME&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns a time as text.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/isemail.html&quot;&gt;ISEMAIL&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns whether the given text string is probably an email address.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/newline.html&quot;&gt;NEWLINE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns a line break character, which causes the character following it
        to appear on the next line.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/parsedate.html&quot;&gt;PARSEDATE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Interprets a text string as a date and returns it.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/parsetime.html&quot;&gt;PARSETIME&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Interprets a text string as a time and returns it.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/regexextractall.html&quot;&gt;REGEXEXTRACTALL&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Extracts the parts of a text string identified by a JavaScript regular
        expression and returns an array with the extracted text.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/regexsplit.html&quot;&gt;REGEXSPLIT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Divides a text string into parts using a regular expression as a
        delimiter, returning the parts as an array.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/reverse.html&quot;&gt;REVERSE&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Reverses the given text string and returns it.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/search.html&quot;&gt;SEARCH&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Finds a text string nestled within another text string and returns its
        position.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/startswith.html&quot;&gt;STARTSWITH&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Returns whether a text string starts with another text string.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/textjoin.html&quot;&gt;TEXTJOIN&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Joins a number of text strings together, separating them with a
        delimiter, and returns the resulting text string.
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td class=&quot;name&quot;&gt;
        &lt;a href=&quot;/learn/formulas/textsplit.html&quot;&gt;TEXTSPLIT&lt;/a&gt;
      &lt;/td&gt;
      &lt;td class=&quot;description&quot;&gt;
        Divides a text string into parts using a delimiter, returning the parts
        as an array.
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;a href=&quot;/learn/formulas/&quot;&gt;Read the complete list of supported functions »&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 20:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/new-functions.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/new-functions.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Arrays and ranges</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Calcapp now supports arrays and ranges. Arrays are collections of values which
  enable many of our new functions and properties. A range is a short-hand for
  constructing arrays with many elements. (Need to sum 100 fields? Easy!)
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our new &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;formula engine&lt;/a&gt; introduces support for &lt;em&gt;arrays&lt;/em&gt;
and &lt;em&gt;ranges&lt;/em&gt;. These are the constructs that make possible many of the
&lt;a href=&quot;/blog/2021/11/12/new-functions.html&quot;&gt;new functions&lt;/a&gt; and properties of &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;this
release&lt;/a&gt;. They enable you to write space-saving
formulas like &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field10)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field10)&lt;/span&gt; and to determine
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;what fields are included in a report&lt;/span&gt; using a formula.&lt;/p&gt;

&lt;p&gt;While arrays and ranges provide great features today, they will become even more
important in the future. In fact, many of the features we are working on for our
next-generation &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;Calcapp 4 project&lt;/a&gt; are built on arrays and ranges.&lt;/p&gt;

&lt;p&gt;So what are arrays? An array is simply a list of values. If you like, you can
think of an array as a value that consists of many values. The values of an
array are known as the &lt;em&gt;elements&lt;/em&gt; of the array.&lt;/p&gt;

&lt;p&gt;A number array, consisting of the numbers 1, -2 and 3, is written like this:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, &lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;2, 3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; &lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;2; 3 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you’re familiar with spreadsheets, you may recognize this construct as an
&lt;em&gt;array constant&lt;/em&gt;. And you’d be right, but arrays in Calcapp are more powerful.&lt;/p&gt;

&lt;p&gt;In Calcapp, array elements can consist of arbitrary calculations which call
functions. Also, their elements don’t have to stay the same as your users go
about using your app. (That means that they aren’t necessarily constant.) In
fact, arrays in Calcapp are very similar to arrays in traditional programming
languages, like JavaScript.&lt;/p&gt;

&lt;p&gt;This formula is also valid, with three elements:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, &lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;2), 3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; &lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;2); 3 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Here’s another valid formula, with two elements:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Field2, &lt;span class=&quot;function&quot; name=&quot;SQRT&quot;&gt;SQRT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4)) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; Field2; &lt;span class=&quot;function&quot; name=&quot;SQRT&quot;&gt;SQRT&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4)) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first element of this array changes when the values of &lt;em&gt;Field1&lt;/em&gt; and &lt;em&gt;Field2&lt;/em&gt;
change.&lt;/p&gt;

&lt;p&gt;Arrays are passed to many of our new functions, including &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;NETWORKDAYS.INTL&quot;&gt;NETWORKDAYS.INTL&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SUMPRODUCT&quot;&gt;SUMPRODUCT&lt;/span&gt;. Also, there are
properties whose formulas must return arrays, including the &lt;em&gt;IncludedFields&lt;/em&gt;
property of &lt;span class=&quot;link property&quot; parent-type=&quot;ResetButton&quot; name=&quot;IncludedFields&quot;&gt;reset buttons&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;email report buttons&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;IncludedFields&quot;&gt;open report buttons&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;ServerRelayButton&quot; name=&quot;IncludedFields&quot;&gt;server relay buttons&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;In order to determine the number of elements of an array, use the new (and
Calcapp-exclusive) &lt;span class=&quot;link function&quot; name=&quot;SIZE&quot;&gt;SIZE&lt;/span&gt; function. This is especially useful in
conjunction with the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function, which returns a filtered
version of an array. With SIZE and FILTER, you can determine the number of array
elements that satisfy a condition.&lt;/p&gt;

&lt;p&gt;Follow the links in the paragraph above to access more information about these
functions and properties. Our newly-revamped documentation includes lots of
examples, making it easy to get started with the new features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; When you enter formulas that use arrays and ranges in Calcapp Creator,
there is no need to press any special keys like &lt;kbd&gt;Ctrl&lt;/kbd&gt; +
&lt;kbd&gt;Shift&lt;/kbd&gt; + &lt;kbd&gt;Enter&lt;/kbd&gt;. That particular key combination is required
by older versions of Microsoft Excel, but does not apply to Calcapp.&lt;/p&gt;

&lt;h2 id=&quot;ranges&quot;&gt;Ranges&lt;/h2&gt;

&lt;p&gt;In spreadsheets, a range refers to a part of the spreadsheet grid, like
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1:B10&lt;/code&gt;, which is a range encompassing the cells A1 and B10 and all the cells
that appear between them:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2021-11-12-arrays/excel-range.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2021-11-12-arrays/excel-range.png&quot; alt=&quot;A range in Microsoft Excel&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spreadsheets differentiate between ranges and array constants. Many spreadsheet
functions (like SUMIF) only work with ranges and not array constants, whereas
others happily work with both (like XLOOKUP). We find that confusing, and you’ll
be happy to learn that Calcapp does not make a distinction between arrays and
ranges.&lt;/p&gt;

&lt;p&gt;Moreover, Calcapp is an app builder and does not have a spreadsheet grid, so
defining a range as a collection of cells does not work for us.&lt;/p&gt;

&lt;p&gt;So what is a range in Calcapp? A range is just an easy short-hand for
constructing arrays. In fact, ranges and arrays look the same to Calcapp
internally.&lt;/p&gt;

&lt;p&gt;To make sense of this, consider a form screen which consists of exactly six
fields, &lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field2&lt;/em&gt;, &lt;em&gt;Field3&lt;/em&gt;, &lt;em&gt;Field4&lt;/em&gt;, &lt;em&gt;Field5&lt;/em&gt; and &lt;em&gt;Field6&lt;/em&gt;, in that
order.&lt;/p&gt;

&lt;p&gt;This formula returns the sum of all of these fields:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Field1, Field2, Field3, Field4, Field5, Field6 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Field1; Field2; Field3; Field4; Field5; Field6 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Can we make this shorter? Yes we can, using ranges:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field6)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field6)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Ranges rely on the order of your form screen elements. The range above formally
contains &lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field6&lt;/em&gt; and all elements that appear between them.&lt;/p&gt;

&lt;p&gt;To drive the point home that ranges are just arrays, this formula also works:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Field1:Field6 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Field1:Field6 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In fact, you can combine ranges and individually-named elements. This formula
returns the sum of &lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field2&lt;/em&gt;, &lt;em&gt;Field3&lt;/em&gt;, &lt;em&gt;Field4&lt;/em&gt; and &lt;em&gt;Field6&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Field1:Field4, Field6 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;({ Field1:Field4; Field6 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Ranges are an effective means of creating arrays containing many elements.
However, it is easy to lose track of what elements they contain, which can have
surprising results. &lt;a href=&quot;/blog/2021/11/12/range-gotcha.html&quot;&gt;This post&lt;/a&gt; explores this topic in depth.&lt;/p&gt;

&lt;h2 id=&quot;most-functions-now-accept-arrays&quot;&gt;Most functions now accept arrays&lt;/h2&gt;

&lt;p&gt;There are many functions which explicitly require their parameters to be arrays,
like &lt;span class=&quot;link function&quot; name=&quot;COUNTIFS&quot;&gt;COUNTIFS&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SUMPRODUCT&quot;&gt;SUMPRODUCT&lt;/span&gt;. What about all the
regular functions that Calcapp has supported since &lt;a href=&quot;/blog/2015/12/10/status.html&quot;&gt;its
inception&lt;/a&gt;, like &lt;span class=&quot;link function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;NPV&quot;&gt;NPV&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;COS&quot;&gt;COS&lt;/span&gt;, surely they don’t support arrays?&lt;/p&gt;

&lt;p&gt;They do, actually, and there are very few that don’t. Consider these
formulas:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;({ &lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4, 4 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;({ &lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4; 4 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first formula returns the absolute value of -4, 4. The second formula
returns the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ 4, 4 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 4; 4 }&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;When a function like ABS, which doesn’t natively support arrays, is given an
array, Calcapp’s formula engine invokes ABS once for every array element and
collects the results in an array. That makes these formulas equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;({ &lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4, 4 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;({ &lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4; 4 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4), &lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(4) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;ADDITIVE_INVERSE&quot;&gt;-&lt;/span&gt;4); &lt;span class=&quot;function&quot; name=&quot;ABS&quot;&gt;ABS&lt;/span&gt;(4) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Microsoft pioneered this behavior with &lt;a href=&quot;https://support.microsoft.com/en-us/office/what-s-new-in-excel-2021-for-windows-f953fe71-8f85-4423-bef9-8a195c7a1100&quot;&gt;Excel 2021&lt;/a&gt;
(though the feature was available earlier to Microsoft 365 subscribers). It is
known as &lt;a href=&quot;https://exceljet.net/glossary/lifting&quot;&gt;lifting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Consider these &lt;span class=&quot;link function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt; formulas:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, 11, 14)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; 11; 14)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, { 11, 5 }, 14)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; { 11; 5 }; 14)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, { 11, 5 }, { 14, 28 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; { 11; 5 }; { 14; 28 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first formula returns the date November 14, 1981. The second formula returns
an array consisting of the dates November 14, 1981 and May 14, 1981. The third
formula returns an array consisting of the dates November 14, 1981 and May 28,
1981.&lt;/p&gt;

&lt;p&gt;The second formula above uses an array for the month parameter. This causes the
formula engine to invoke the DATE function twice, first pairing 1981 with 11 and
14, and then pairing 1981 with 5 and 14. That makes these formulas equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, { 11, 5 }, 14)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; { 11; 5 }; 14)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, 11, 14), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, 5, 14) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; 11; 14); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; 5; 14) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The third formula, &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, { 11, 5 }, { 14, 28 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; { 11; 5 }; { 14; 28 })&lt;/span&gt;, uses
arrays for both the month and day parameters. They both contain two elements,
causing the formula engine to invoke the DATE function twice, first pairing 1981
with 11 and 14, and then pairing 1981 with 5 and 28. That makes these formulas
equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, { 11, 5 }, { 14, 28 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; { 11; 5 }; { 14; 28 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, 11, 14), &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, 5, 28) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; 11; 14); &lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; 5; 28) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(What happens if you pass arrays that don’t have the same number of elements?
The returned array will contain &lt;span class=&quot;link function&quot; name=&quot;NA&quot;&gt;not available&lt;/span&gt; values.)&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;ABS&quot;&gt;documentation for ABS&lt;/span&gt; (click &lt;strong&gt;Details&lt;/strong&gt;) states that
ABS returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Number or { Number }&lt;/code&gt; (a number or an array of numbers). That’s how
you spot a function in our documentation that returns an array if one or several
parameters are arrays — we call them &lt;em&gt;array-capable functions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;(Technically, an array-capable function returns an array if one or several of
its parameters, which are documented to either accept a regular value or an
array, are invoked with arrays.)&lt;/p&gt;

&lt;p&gt;Explore all the examples in our &lt;a href=&quot;/learn/formulas/&quot;&gt;formula&lt;/a&gt; and &lt;a href=&quot;/learn/properties/&quot;&gt;property
documentation&lt;/a&gt; to find lots of helpful tips on where you
can use arrays with regular functions to great effect.&lt;/p&gt;

&lt;h2 id=&quot;arrays-and-matrix-functions&quot;&gt;Arrays and matrix functions&lt;/h2&gt;

&lt;p&gt;Spreadsheets and Calcapp alike support specialized math functions for handling
matrices, such as &lt;span class=&quot;link function&quot; name=&quot;MMULT&quot;&gt;MMULT&lt;/span&gt;. A matrix is a two-dimensional array,
which is an array whose elements are arrays. A matrix can be visualized as a
two-dimensional area containing values, in contrast to a regular,
one-dimensional array which can be visualized as a single line containing
values.&lt;/p&gt;

&lt;p&gt;Matrices are written differently in Calcapp compared to most spreadsheets. For
instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=MMULT({ 3, 5; 1, 2 }, { 2, 6; 1, 1 })&lt;/code&gt; (written &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=MMULT({ 3; 5\ 1; 2
}; { 2; 6\ 1; 1 })&lt;/code&gt; with decimal commas) is written like this in Calcapp:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;MMULT&quot;&gt;MMULT&lt;/span&gt;({{ 3, 5 }, { 1, 2 }}, {{ 2, 6 }, { 1, 1 }})&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;MMULT&quot;&gt;MMULT&lt;/span&gt;({{ 3; 5 }; { 1; 2 }}; {{ 2; 6 }; { 1; 1 }})&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Calcapp’s syntax for two-dimensional arrays is closer to what traditional
programming uses than the syntax used by spreadsheets. We designed it this way
as we prefer to use semicolons to separate &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html#action-formulas&quot;&gt;statements in action
formulas&lt;/a&gt;, which will be the focus of our next release.&lt;/p&gt;

&lt;h2 id=&quot;further-reading-on-arrays&quot;&gt;Further reading on arrays&lt;/h2&gt;

&lt;p&gt;There are another four blog posts describing our new array support:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/array-if.html&quot;&gt;Feature: Use IF to conditionally include array elements&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/array-concatenation.html&quot;&gt;Feature: Use | to join arrays together with other arrays and
values&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/debug-arrays.html&quot;&gt;Tip: Debug arrays by inspecting their elements&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/2021/11/12/range-gotcha.html&quot;&gt;Tip: Avoid gotchas when adding text boxes and buttons in the middle of a
range&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 19:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/arrays.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/arrays.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Look up values with XLOOKUP</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Excel 2021&apos;s XLOOKUP function is now fully supported. It does everything
  VLOOKUP and HLOOKUP do and more. Use an app to convert table data to XLOOKUP
  formulas.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;&lt;strong&gt;August 11, 2023 update:&lt;/strong&gt; We now recommend that you use the &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data
editor&lt;/a&gt; to import and edit spreadsheet data. It is significantly
easier to use than the app described here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original text:&lt;/strong&gt; People have been asking us for a way to look up values since
we &lt;a href=&quot;/blog/2015/12/10/status.html&quot;&gt;launched our first beta&lt;/a&gt;. In 2018, we introduced support
for the &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; function and wrote an app that makes it easy to
convert tabular data to CHOOSE formulas, alleviating some of the pain (see
below).&lt;/p&gt;

&lt;p&gt;We’re happy to announce that we now have full support for the
&lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; function, which Microsoft &lt;a href=&quot;https://support.microsoft.com/en-us/office/what-s-new-in-excel-2021-for-windows-f953fe71-8f85-4423-bef9-8a195c7a1100&quot;&gt;introduced with Excel
2021&lt;/a&gt; (and has been available to Microsoft 365 subscribers
for a while now). If you prefer using &lt;span class=&quot;link function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;MATCH&quot;&gt;MATCH&lt;/span&gt;, we support them too (along with the new
&lt;span class=&quot;link function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;, which has all the features of XLOOKUP).&lt;/p&gt;

&lt;p&gt;This formula returns 300, because the sought value, 30, is the third element in
the first array, which causes XLOOKUP to return the third element in the second
array, 300:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(30, { 10, 20, 30 }, { 100, 200, 300 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(30; { 10; 20; 30 }; { 100; 200; 300 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first array is known as the &lt;em&gt;lookup array&lt;/em&gt; and the second array is known as
the &lt;em&gt;result array&lt;/em&gt;. We have written an app that does the conversion from table
data to formulas, see below.&lt;/p&gt;

&lt;p&gt;Don’t miss our extensive documentation covering &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;MATCH&quot;&gt;MATCH&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;, with
lots of examples.&lt;/p&gt;

&lt;h2 id=&quot;xlookup-versus-index-and-xmatch&quot;&gt;XLOOKUP versus INDEX and XMATCH&lt;/h2&gt;

&lt;p&gt;Looking up a value involves two steps. First, an element matching the sought
value in the lookup array must be found. Then, the corresponding element in the
result array is returned. If the second element in the lookup array matches the
sought value, the second element in the result array is returned.&lt;/p&gt;

&lt;p&gt;These two steps can be performed explicitly, using &lt;span class=&quot;link function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt; or
&lt;span class=&quot;link function&quot; name=&quot;MATCH&quot;&gt;MATCH&lt;/span&gt; (XMATCH is easier to use and offers more features) and
&lt;span class=&quot;link function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;. MATCH and XMATCH return the position of the sought value
in the array. INDEX is then given this position as its second parameter, and
returns the element at that position from the array given as its first
parameter.&lt;/p&gt;

&lt;p&gt;As a result, these formulas are equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(30, { 10, 20, 30 }, { 100, 200, 300 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(30; { 10; 20; 30 }; { 100; 200; 300 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;({ 100, 200, 300 }, &lt;span class=&quot;function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;(30, { 10, 20, 30 }))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;INDEX&quot;&gt;INDEX&lt;/span&gt;({ 100; 200; 300 }; &lt;span class=&quot;function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;(30; { 10; 20; 30 }))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Using XLOOKUP directly leads to shorter formulas that may be easier to
understand. Combining XMATCH with INDEX has the advantage of giving you more
flexibility. Which variant you choose is mostly a matter of personal preference.&lt;/p&gt;

&lt;h2 id=&quot;what-about-vlookup-and-hlookup&quot;&gt;What about VLOOKUP and HLOOKUP?&lt;/h2&gt;

&lt;p&gt;There is nothing that VLOOKUP and HLOOKUP can do that XLOOKUP doesn’t handle. In
fact, XLOOKUP is preferable even if you use Excel, as it has more features and
more sensible defaults. (You get exact matches by default.) If you have been
hoping that Calcapp would some day support something like VLOOKUP and HLOOKUP,
that day has finally come.&lt;/p&gt;

&lt;p&gt;Calcapp probably won’t support VLOOKUP and HLOOKUP in the future, primarily
because these functions are tied to a spreadsheet grid. Calcapp isn’t a
spreadsheet, and there is no grid. When you use VLOOKUP, you specify a range
encompassing your table (or parts of your table) and a column number (counting
from the left) of the column containing the values you seek. Without a grid,
that doesn’t make sense.&lt;/p&gt;

&lt;p&gt;XLOOKUP is different, in that it accepts two arrays. (In Excel, it also works
with ranges, which are tied to the spreadsheet grid.) Now that Calcapp has a new
formula engine which supports arrays, we can easily add support for something
like XLOOKUP.&lt;/p&gt;

&lt;p&gt;We are thrilled that Microsoft happened to introduce a new lookup function at
roughly the same time that we needed to add one to Calcapp — and at that, a
lookup function that is fully compatible with our new formula engine. We would
much rather support a lookup function pioneered by Microsoft than come up with
our own variant.&lt;/p&gt;

&lt;h2 id=&quot;converting-table-data-to-formulas&quot;&gt;Converting table data to formulas&lt;/h2&gt;

&lt;p&gt;While our &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; support is complete, there is an important
caveat. All data needs to be put into formulas, because Calcapp still does not
have native support for tables.&lt;/p&gt;

&lt;p&gt;We recognize that being able to import data directly to a table in Calcapp
Creator would be preferable. That feature is coming in our next-generation
&lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;Calcapp 4 project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The good news is that we have created an app that does the conversion for you.
To demonstrate how to use it, we’ll use this small sample table:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Product&lt;/th&gt;
    &lt;th&gt;Price&lt;/th&gt;
    &lt;th&gt;Color&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 1&lt;/td&gt;
    &lt;td&gt;5.20&lt;/td&gt;
    &lt;td&gt;Indigo&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 2&lt;/td&gt;
    &lt;td&gt;5.20&lt;/td&gt;
    &lt;td&gt;Ivory&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 3&lt;/td&gt;
    &lt;td&gt;5.92&lt;/td&gt;
    &lt;td&gt;Khaki&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 4&lt;/td&gt;
    &lt;td&gt;5.92&lt;/td&gt;
    &lt;td&gt;Lavender&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 5&lt;/td&gt;
    &lt;td&gt;7.04&lt;/td&gt;
    &lt;td&gt;Silver&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 6&lt;/td&gt;
    &lt;td&gt;7.04&lt;/td&gt;
    &lt;td&gt;Snow&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 7&lt;/td&gt;
    &lt;td&gt;7.55&lt;/td&gt;
    &lt;td&gt;Tan&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 8&lt;/td&gt;
    &lt;td&gt;7.55&lt;/td&gt;
    &lt;td&gt;Teal&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 9&lt;/td&gt;
    &lt;td&gt;9.59&lt;/td&gt;
    &lt;td&gt;Thistle&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Sample 10&lt;/td&gt;
    &lt;td&gt;9.59&lt;/td&gt;
    &lt;td&gt;Violet&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;For this exercise, we’ll need to copy column data from the table, which only
works from a spreadsheet.
&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1Xw73jH8akwmFKZj3cklQykCNaY_oddCXX--J4LrofDc&quot; target=&quot;google-sheets&quot;&gt;Here is the table, as a Google Sheets spreadsheet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To look up the price based on the product name (contained in the &lt;em&gt;Product&lt;/em&gt; text
drop-down field), we need to generate an XLOOKUP formula. To do so, we use the
app.&lt;/p&gt;

&lt;p&gt;Here’s an embedded version of the app, which you can also
&lt;a href=&quot;https://connect.calcapp.net/?app=dtoyel&quot; target=&quot;connect&quot;&gt;run as a
stand-alone app&lt;/a&gt;:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 665px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=dtoyel&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;To generate an XLOOKUP formula locating prices, follow these steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Write “Product” in the &lt;strong&gt;Sought value&lt;/strong&gt; field, which causes the first
parameter to the generated XLOOKUP formula to be set to “Product”.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Select all product names from the spreadsheet. Select &lt;strong&gt;Sample 1&lt;/strong&gt; through
&lt;strong&gt;Sample 10&lt;/strong&gt;, press &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;C&lt;/kbd&gt; (or
&lt;kbd&gt;⌘&lt;/kbd&gt;+&lt;kbd&gt;C&lt;/kbd&gt; if you’re on a Mac) to copy the selection to the
clipboard.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Paste this data into the &lt;strong&gt;Lookup values&lt;/strong&gt; field in the app. Click the empty
field, and then press &lt;kbd&gt;Ctrl&lt;/kbd&gt;+&lt;kbd&gt;V&lt;/kbd&gt; (or
&lt;kbd&gt;⌘&lt;/kbd&gt;+&lt;kbd&gt;V&lt;/kbd&gt; if you’re on a Mac).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copy all prices to the clipboard.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Paste this data into the &lt;strong&gt;Result values&lt;/strong&gt; field in the app.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The app generates the correct formula for you:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(Product, { &quot;Sample 1&quot;, &quot;Sample 2&quot;, &quot;Sample 3&quot;, &quot;Sample 4&quot;, &quot;Sample 5&quot;, &quot;Sample 6&quot;, &quot;Sample 7&quot;, &quot;Sample 8&quot;, &quot;Sample 9&quot;, &quot;Sample 10&quot; }, { 5.20, 5.20, 5.92, 5.92, 7.04, 7.04, 7.55, 7.55, 9.59, 9.59 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(Product; { &quot;Sample 1&quot;; &quot;Sample 2&quot;; &quot;Sample 3&quot;; &quot;Sample 4&quot;; &quot;Sample 5&quot;; &quot;Sample 6&quot;; &quot;Sample 7&quot;; &quot;Sample 8&quot;; &quot;Sample 9&quot;; &quot;Sample 10&quot; }; { 5,20; 5,20; 5,92; 5,92; 7,04; 7,04; 7,55; 7,55; 9,59; 9,59 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you repeat the same steps for the &lt;strong&gt;Color&lt;/strong&gt; column, this formula is
generated:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(Product, { &quot;Sample 1&quot;, &quot;Sample 2&quot;, &quot;Sample 3&quot;, &quot;Sample 4&quot;, &quot;Sample 5&quot;, &quot;Sample 6&quot;, &quot;Sample 7&quot;, &quot;Sample 8&quot;, &quot;Sample 9&quot;, &quot;Sample 10&quot; }, { &quot;Indigo&quot;, &quot;Ivory&quot;, &quot;Khaki&quot;, &quot;Lavender&quot;, &quot;Silver&quot;, &quot;Snow&quot;, &quot;Tan&quot;, &quot;Teal&quot;, &quot;Thistle&quot;, &quot;Violet&quot; })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(Product; { &quot;Sample 1&quot;; &quot;Sample 2&quot;; &quot;Sample 3&quot;; &quot;Sample 4&quot;; &quot;Sample 5&quot;; &quot;Sample 6&quot;; &quot;Sample 7&quot;; &quot;Sample 8&quot;; &quot;Sample 9&quot;; &quot;Sample 10&quot; }; { &quot;Indigo&quot;; &quot;Ivory&quot;; &quot;Khaki&quot;; &quot;Lavender&quot;; &quot;Silver&quot;; &quot;Snow&quot;; &quot;Tan&quot;; &quot;Teal&quot;; &quot;Thistle&quot;; &quot;Violet&quot; })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Note that the app automatically detects if the values are numbers or text. If
they are numbers (potentially starting with a currency symbol, such as “$”), the
elements of the generated array are not quoted. For this to work, you need to
ensure that you have selected the correct decimal separator from the &lt;strong&gt;Decimal
separator&lt;/strong&gt; text drop-down field.&lt;/p&gt;

&lt;p&gt;To learn how the app was built, we have written &lt;a href=&quot;/blog/2021/11/12/xlookup-generator.html&quot;&gt;a blog post that walks you
through it&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;xlookup-versus-choose&quot;&gt;XLOOKUP versus CHOOSE&lt;/h2&gt;

&lt;p&gt;Associating values from a table with the options available from a text drop-down
field can also be done using the &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; function and the
&lt;span class=&quot;link property&quot; parent-type=&quot;TextDropDownField&quot; name=&quot;Index&quot;&gt;Index&lt;/span&gt; property of text drop-down fields. We
provide &lt;a href=&quot;/blog/2018/04/06/tabular-data-drop-downs.html&quot;&gt;instructions&lt;/a&gt; and &lt;a href=&quot;/blog/2018/04/06/column-converter.html&quot;&gt;an app&lt;/a&gt;
that generates such formulas.&lt;/p&gt;

&lt;p&gt;CHOOSE formulas have the advantage that they are compact. They rely on the
position of the option selected by the user and therefore don’t need to be
provided with lookup values. They can also be expected to be faster.&lt;/p&gt;

&lt;p&gt;However, CHOOSE formulas are very limited compared to XLOOKUP formulas. With
XLOOKUP, you can look up any value you desire, and take advantage of all the
features that XLOOKUP offers, such as inexact text matching and the like
(&lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;learn more&lt;/span&gt;). CHOOSE formulas are mostly practical to
use when you need to associate a single value with an option selected from a
text drop-down field.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 18:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/xlookup.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/xlookup.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Use SUMIF, SUMIFS and others like them</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  AVERAGEIF, COUNTIF, MINIFS, MAXIFS, PRODUCTIF, SUMIF and variants are now
  supported. Use our formula fragment extension for complex conditions.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;While Calcapp has supported &lt;a href=&quot;/blog/2016/05/25/244-functions.html&quot;&gt;hundreds of functions&lt;/a&gt; since 2016,
there have been conspicuous holes in our function coverage. Most notably, we
have not supported the popular conditional functions &lt;span class=&quot;link function&quot; name=&quot;AVERAGEIF&quot;&gt;AVERAGEIF&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;AVERAGEIFS&quot;&gt;AVERAGEIFS&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;COUNTIF&quot;&gt;COUNTIF&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;COUNTIFS&quot;&gt;COUNTIFS&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;MINIFS&quot;&gt;MINIFS&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;MAXIFS&quot;&gt;MAXIFS&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;As you have probably gathered from the fact that the preceding paragraph is full
of links to our formula documentation, we now have full support for these
functions. We have also added support for &lt;span class=&quot;link function&quot; name=&quot;PRODUCTIF&quot;&gt;PRODUCTIF&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;PRODUCTIFS&quot;&gt;PRODUCTIFS&lt;/span&gt;, which are (as far as we know) exclusive to Calcapp
and have been requested by spreadsheet users for years. They work precisely like
the &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt; functions, but multiply
numbers instead of adding them together.&lt;/p&gt;

&lt;p&gt;It is possible to simulate these functions using just the &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;
function and regular calculations. However, that tends to produce very long
formulas that are hard to maintain. With support for these conditional
functions, we now enable many more spreadsheets to be easily converted to apps,
with no hoops to jump through.&lt;/p&gt;

&lt;h2 id=&quot;what-can-these-functions-be-used-for&quot;&gt;What can these functions be used for?&lt;/h2&gt;

&lt;p&gt;In their simplest form, these conditional functions accept an array as their
first parameter and then apply an operation on its elements (like adding them
together), but only if the element under consideration passes a test (a
&lt;em&gt;condition&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;For instance, you can easily get the sum of all numbers of an array that are
greater than 1. This formula does just that, using &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1, 2, 3 }, &quot;&amp;gt;1&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1; 2; 3 }; &quot;&amp;gt;1&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above returns 5 (&lt;span class=&quot;formula decimalpoint&quot;&gt;2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3&lt;/span&gt;). It does not return 6
(&lt;span class=&quot;formula decimalpoint&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3&lt;/span&gt;), as only 2 and 3 are greater than 1, as specified
by the &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;&amp;gt;1&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;&amp;gt;1&quot;&lt;/span&gt; parameter.&lt;/p&gt;

&lt;p&gt;This formula returns the sum of all field values of the &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field10&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field10&lt;/span&gt; range which are less than 3:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;(Field1:Field10, &quot;&amp;lt;3&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;(Field1:Field10; &quot;&amp;lt;3&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Before &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;this release&lt;/a&gt;, an app author would have had to
invoke &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; multiple times to achieve the same result:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field2) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field3) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field4 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field4) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field5 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field5) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field6 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field6) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field7 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field7) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field8 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field8) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field9 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field9) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field10 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3, Field10)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field1) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field2 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field2) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field3) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field4 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field4) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field5 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field5) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field6 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field6) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field7 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field7) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field8 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field8) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field9 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field9) &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field10 &lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 3; Field10)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you need multiple conditions, use the &lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt;({ 10, 20, 30 }, { 1, 2, 3 }, &quot;&amp;gt;1&quot;, { &quot;Eve&quot;, &quot;Eve&quot;, &quot;Bill&quot; }, &quot;Eve&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt;({ 10; 20; 30 }; { 1; 2; 3 }; &quot;&amp;gt;1&quot;; { &quot;Eve&quot;; &quot;Eve&quot;; &quot;Bill&quot; }; &quot;Eve&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above returns 20, because that is the only element of the first
array where both corresponding elements in the other arrays satisfy their
conditions.&lt;/p&gt;

&lt;p&gt;In the second array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3 }&lt;/span&gt;, 2 and 3 satisfy the
&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;&amp;gt;1&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;&amp;gt;1&quot;&lt;/span&gt; condition, as they are both greater than 1. In the third
array, &lt;span class=&quot;formula decimalpoint&quot;&gt;{ &quot;Eve&quot;, &quot;Eve&quot;, &quot;Bill&quot; }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &quot;Eve&quot;; &quot;Eve&quot;; &quot;Bill&quot; }&lt;/span&gt;, the two first elements
satisfy the &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;Eve&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;Eve&quot;&lt;/span&gt; condition, requiring matching elements to
be equal to “Eve”. In other words, the second and third elements of the second
array match their corresponding condition, while the first and second elements
of the third array match their corresponding condition. As such, only the second
element of the first array is considered, resulting in a return value of 20.&lt;/p&gt;

&lt;p&gt;As noted, the &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt; functions above
calculate sums (adding numbers together). The &lt;span class=&quot;link function&quot; name=&quot;PRODUCTIF&quot;&gt;PRODUCTIF&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;PRODUCTIFS&quot;&gt;PRODUCTIFS&lt;/span&gt; functions calculate products (multiplying numbers
together). &lt;span class=&quot;link function&quot; name=&quot;AVERAGEIF&quot;&gt;AVERAGEIF&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;AVERAGEIFS&quot;&gt;AVERAGEIFS&lt;/span&gt; calculate
averages and &lt;span class=&quot;link function&quot; name=&quot;COUNTIF&quot;&gt;COUNTIF&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;COUNTIFS&quot;&gt;COUNTIFS&lt;/span&gt; count how many
elements satisfy the given condition or conditions.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;MINIFS&quot;&gt;MINIFS&lt;/span&gt; finds the smallest number among a set of numbers that
satisfy one or several conditions. Conversely, &lt;span class=&quot;link function&quot; name=&quot;MAXIFS&quot;&gt;MAXIFS&lt;/span&gt; finds the
largest number among a set of numbers that satisfy one or several conditions.&lt;/p&gt;

&lt;h2 id=&quot;comparing-array-elements-to-field-values&quot;&gt;Comparing array elements to field values&lt;/h2&gt;

&lt;p&gt;The text strings that need to be given to these functions lend themselves well
to comparing elements against constant values. However, what if you need to
compare elements against field values (or any other values derived through
formulas)?&lt;/p&gt;

&lt;p&gt;In that common case, you need to use the text concatenation operator,
&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt;. Here’s a formula returning the sum of all values that are
greater than the value of &lt;em&gt;Field1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1, 2, 3 }, &quot;&amp;gt;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Field1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1; 2; 3 }; &quot;&amp;gt;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Field1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns the sum of all field values of the
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field2:Field10&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field2:Field10&lt;/span&gt; range which are less than
or equal to &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;(Field2:Field10, &quot;&amp;lt;=&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Field1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;(Field2:Field10; &quot;&amp;lt;=&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Field1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above uses a &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;range&lt;/a&gt; to construct an array containing many
elements. It is easy to lose track of what elements a range contains, though,
which can have surprising results. &lt;a href=&quot;/blog/2021/11/12/range-gotcha.html&quot;&gt;This post&lt;/a&gt; explores this topic
in depth.&lt;/p&gt;

&lt;h2 id=&quot;a-word-on-decimal-separators&quot;&gt;A word on decimal separators&lt;/h2&gt;

&lt;p&gt;Calcapp allows you to write formulas &lt;a href=&quot;/blog/2021/11/12/decimal-separator.html&quot;&gt;using either decimal points or decimal
commas&lt;/a&gt;. You might think that the decimal separator
preference you have specified for formulas would apply to the text string given
to conditional functions, but that is not the case.&lt;/p&gt;

&lt;p&gt;Conditional functions like SUMIF and SUMIFS do support both decimal points and
decimal commas. When they need to interpret a period or a comma in the text
string you supply, they don’t rely on your decimal separator formula preference,
they rely on the language of the app.&lt;/p&gt;

&lt;p&gt;That means that if your app is in German, you must use a comma as a decimal
separator, even if your preference for formulas calls for using a decimal point:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;SUMIF({ 1, 2, 3 }, &quot;&amp;gt;1,1&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;SUMIF({ 1, 2, 3 }, &quot;&amp;gt;1,1&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The same logic applies in reverse if you prefer using decimal commas in
formulas, but your app is in US English:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;SUMIF({ 1, 2, 3 }; &quot;&amp;gt;1.1&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;SUMIF({ 1, 2, 3 }; &quot;&amp;gt;1.1&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This situation should be rare, but it’s something to be aware of if you get
surprising results.&lt;/p&gt;

&lt;p&gt;The reason we designed it this way is because when you join text strings like
“&amp;lt;=” together with field values using &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt;, Calcapp uses the
decimal separator of the language the app has been configured to use when
converting the field value to a text string. For that reason, the conditional
functions must do the same.&lt;/p&gt;

&lt;p&gt;Of course, if you want to sidestep this issue completely, you can use a formula
fragment instead of a textual condition. That is the subject for our next
section.&lt;/p&gt;

&lt;h2 id=&quot;using-formula-fragments-instead-of-textual-conditions&quot;&gt;Using formula fragments instead of textual conditions&lt;/h2&gt;

&lt;p&gt;The conditional functions are quite limited in terms of what conditions you can
express. With a function like &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;, you can only express a
single condition. Functions like &lt;span class=&quot;link function&quot; name=&quot;SUMIFS&quot;&gt;SUMIFS&lt;/span&gt; enable multiple
conditions to be expressed, but all conditions need to match — there is no room
for including a value which matches one of two conditions (logical &lt;em&gt;or&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;We have introduced extensions specific to Calcapp which enable you to use
formula fragments to determine if an element should or should not be included. A
formula fragment can use any function or operator, meaning that they are
infinitely flexible.&lt;/p&gt;

&lt;p&gt;In a formula fragment, the element under consideration is available as the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Element&lt;/code&gt; value. These formulas are equivalent, with the second one using a
formula fragment:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1, 2, 3 }, &quot;&amp;gt;1&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1; 2; 3 }; &quot;&amp;gt;1&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1, 2, 3 }, Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 1)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1; 2; 3 }; Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 1)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Note that the formula fragment is not a text string, but just a regular part of
the overall formula. That means that you can easily restrict elements to those
that are greater than 1 &lt;em&gt;or&lt;/em&gt; are odd (&lt;span class=&quot;link binaryOperator&quot; name=&quot;||&quot;&gt;||&lt;/span&gt; means “or”):&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1, 2, 3 }, (Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;ISODD&quot;&gt;ISODD&lt;/span&gt;(Element))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;({ 1; 2; 3 }; (Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 1) &lt;span class=&quot;binaryOperator&quot; name=&quot;DISJUNCTION&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;ISODD&quot;&gt;ISODD&lt;/span&gt;(Element))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In practice, the formula above returns 6 (&lt;span class=&quot;formula decimalpoint&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 3&lt;/span&gt;), as 1 is
included on account of being an odd number.&lt;/p&gt;

&lt;p&gt;Refer to &lt;a href=&quot;/learn/formulas/&quot;&gt;our documentation&lt;/a&gt; for these functions for many
more examples.&lt;/p&gt;

&lt;p&gt;When you use a formula fragment with ranges, you may encounter error messages if
your range inadvertently contains, say, text boxes and buttons. &lt;a href=&quot;/blog/2021/11/12/range-gotcha.html&quot;&gt;This
post&lt;/a&gt; explores this topic in depth.&lt;/p&gt;

&lt;h2 id=&quot;using-filter-instead-of-the-specialized-conditional-functions&quot;&gt;Using FILTER instead of the specialized conditional functions&lt;/h2&gt;

&lt;p&gt;The work &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt; performs can be divided into two parts: filtering
out the unwanted elements from the array and then returning the sum of the
elements which made the cut. Just like &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; invocations can
be &lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;replaced by using both INDEX and XMATCH&lt;/a&gt;, SUMIF and the other
conditional functions can be replaced by using the new &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;
function together with specialized functions calculating a result (for SUMIF,
that specialized function is &lt;span class=&quot;link function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt; — or &lt;span class=&quot;link function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt; if
you are feeling adventurous).&lt;/p&gt;

&lt;p&gt;FILTER accepts an array as its first parameter and returns a version of this
array which only contains elements that have passed a test you have supplied.&lt;/p&gt;

&lt;p&gt;The most commonly used variant of FILTER expresses this test as a logical array
given as the second parameter, which should contain the same number of elements
as the array to filter. If an element of the second array is TRUE, the
corresponding element of the array to filter is part of the returned array. If
it is FALSE, the element is dropped.&lt;/p&gt;

&lt;p&gt;This formula returns an array of fields whose values are greater than 4:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3, Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3; Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If we combine FILTER with SUM, we can replicate the &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;
function. These formulas are equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;(Field1:Field3, &quot;&amp;gt;4&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;(Field1:Field3; &quot;&amp;gt;4&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3, Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3; Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Of course, the SUMIF formula is much shorter and is likely easier to read. By
combining FILTER with SUM, though, we gain flexibility, and a deeper
understanding of how the final result is calculated. Use whichever variant you
are most comfortable with.&lt;/p&gt;

&lt;p&gt;To explore these functions — and alternatives to using them — be sure to check
out our full &lt;a href=&quot;/learn/formulas/&quot;&gt;formula documentation&lt;/a&gt;. These functions are
available in the &lt;em&gt;Math&lt;/em&gt; and &lt;em&gt;Statistical&lt;/em&gt; categories.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 17:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/conditional-functions.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/conditional-functions.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Send formula-driven emails</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Fully determine the bodies of emails you send using formulas. You can also use
  formulas to set text that appears before or after field values in reports.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Over the years, we have steadily added features that help you more fully
customize the emails sent from your apps. When reports launched in 2016, there
were &lt;a href=&quot;/blog/2016/10/18/reporting-email.html&quot;&gt;very few report-related options&lt;/a&gt; in the inspector. We
&lt;a href=&quot;/blog/2016/11/18/reporting-improvements.html&quot;&gt;quickly added&lt;/a&gt; the ability to choose whether screen
names and blank values should be part of reports, and whether sent fields should
be reset afterwards. Towards the end of the year, we added &lt;a href=&quot;/blog/2016/12/22/pdf-reports.html&quot;&gt;PDF
reports&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In early 2017, you got the ability to set the &lt;a href=&quot;/blog/2017/02/24/report-sender.html&quot;&gt;sender of emails&lt;/a&gt;,
and in 2018 we made it possible to &lt;a href=&quot;/blog/2018/03/06/subject-line.html&quot;&gt;change the subject line&lt;/a&gt;,
potentially using a formula. Finally, a &lt;a href=&quot;/blog/2019/04/12/reporting.html&quot;&gt;grab bag of improvements landed in
2019&lt;/a&gt;, including the ability to set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reply-To&lt;/code&gt; field and the
ability to set the file names of attached files, possibly using a formula.&lt;/p&gt;

&lt;h2 id=&quot;setting-the-email-body&quot;&gt;Setting the email body&lt;/h2&gt;

&lt;p&gt;It’s 2021, and the time has come to let you set the body of emails sent through
your apps using formulas, making all email aspects fully customizable. With this
feature, you can finally communicate with your users using plain English (or any
other language), instead of sending dry field values in a table.&lt;/p&gt;

&lt;p&gt;This feature is enabled by the new &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;Body&lt;/span&gt;
property of email reports buttons. Consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;Dear &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Name &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;,&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;The weight is&lt;br /&gt;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(Weight) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; lbs.&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;Dear &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; Name &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;,&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;The weight is&lt;br /&gt;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;(Weight) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; lbs.&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above sets the email body to something like the following:&lt;/p&gt;

&lt;pre&gt;
Dear Sally,

The weight is 23.30 lbs.
&lt;/pre&gt;

&lt;p&gt;The new &lt;span class=&quot;link function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt; function returns a line break character (and is
fully equivalent to &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHAR&quot;&gt;CHAR&lt;/span&gt;(10)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHAR&quot;&gt;CHAR&lt;/span&gt;(10)&lt;/span&gt;). It makes it easy to construct
email bodies consisting of multiple lines, and multiple paragraphs.&lt;/p&gt;

&lt;p&gt;If this property is not set, a default body is used. If the format of the email
report button calls for a file to be attached (containing, say, a PDF document),
the default body includes instructions in English on how to open the attached
file. By setting a body explicitly through this property, you can fully
determine the email body yourself.&lt;/p&gt;

&lt;p&gt;There is one thing this new feature won’t enable you to do: send emails with
images and formatted text. You also can’t send PDF documents containing images
and formatted text. For the latter use case, there are lots of great third-party
services you can integrate with your apps to realize this functionality. We
&lt;a href=&quot;/blog/2020/08/17/zapier-pdf.html&quot;&gt;wrote a blog post&lt;/a&gt; walking you through two such services last year.&lt;/p&gt;

&lt;p&gt;Refer to &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;our complete documentation&lt;/span&gt; to
learn more and to access formula examples demonstrating how the new feature can
be used.&lt;/p&gt;

&lt;h2 id=&quot;setting-the-text-that-appears-before-and-after-field-values&quot;&gt;Setting the text that appears before and after field values&lt;/h2&gt;

&lt;p&gt;The &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Body&quot;&gt;email body property&lt;/span&gt; sets the body of
emails you send. If the format of the email is text, field values are included
directly in the body, appearing directly after the text set through the &lt;em&gt;Body&lt;/em&gt;
property.&lt;/p&gt;

&lt;p&gt;There is a new property, &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Prologue&quot;&gt;Prologue&lt;/span&gt;, which
allows you to set the text that appears before the field values. It is pretty
much equivalent to the &lt;em&gt;Body&lt;/em&gt; property if the format is set to text (the
prologue text appears after the body text). To set the text that appears after
field values, use the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Epilogue&quot;&gt;Epilogue&lt;/span&gt; property.&lt;/p&gt;

&lt;p&gt;If the format of the email calls for a file to be attached, containing CSV or
PDF data, the &lt;em&gt;Body&lt;/em&gt; property determines the body of the email itself, while the
&lt;em&gt;Prologue&lt;/em&gt; and &lt;em&gt;Epilogue&lt;/em&gt; properties apply to the attached file. You can even
ask Calcapp not to include any field values at all, meaning that you can fully
determine the text contents of an attached PDF file using a formula.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Prologue&lt;/em&gt; and &lt;em&gt;Epilogue&lt;/em&gt; properties apply not just to email report buttons,
but also to open report buttons (which enable files to be downloaded directly to
a user’s device).&lt;/p&gt;

&lt;p&gt;Refer to the our newly-revamped property documentation to learn more and to
access examples demonstrating the new features. Here’s documentation for the
&lt;em&gt;Prologue&lt;/em&gt; property of &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Prologue&quot;&gt;email report buttons&lt;/span&gt; and &lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;Prologue&quot;&gt;open report buttons&lt;/span&gt;.
Finally, here’s documentation for the &lt;em&gt;Epilogue&lt;/em&gt; property of
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Epilogue&quot;&gt;email report buttons&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;Epilogue&quot;&gt;open report buttons&lt;/span&gt;.&lt;/p&gt;

&lt;h2 id=&quot;calcapp-branding-and-reports&quot;&gt;Calcapp branding and reports&lt;/h2&gt;

&lt;p&gt;Prior to &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;this release&lt;/a&gt;, generated reports differed
somewhat depending on if your app was on a White Label plan or not. If your app
was on a White Label plan, no mention was made of Calcapp, in any context.&lt;/p&gt;

&lt;p&gt;If your app was not on a White Label plan and you sent reports by email,
attached PDF files included a blurb before the field values stating the name of
your app, the date and the fact that Calcapp had been used to generate the
report. Attached CSV files, on the other hand, did not mention Calcapp. Finally,
email bodies for apps not on a White Label plan mentioned Calcapp in the footer.&lt;/p&gt;

&lt;p&gt;These rules also applied to reports downloaded directly to a user’s device.
Downloaded plain text files, or HTML documents, did not mention Calcapp,
regardless of what plan your app was on.&lt;/p&gt;

&lt;p&gt;If you don’t make use of any of the new properties &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Body&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Prologue&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Epilogue&lt;/code&gt; and your app is not on a White Label plan, the only change you will
see is that generated PDF files look a little different. Specifically, nothing
appears before the field values. Rather, a short sentence (“Generated by
Calcapp.”) now appears after the field values.&lt;/p&gt;

&lt;p&gt;If you want your report to look mostly identical to the way it looked before,
complete with the current date and time, associate a formula like the following
with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Prologue&lt;/code&gt; property of the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Prologue&quot;&gt;email report button&lt;/span&gt; or the &lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;Prologue&quot;&gt;open report button&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;This report has been sent from the &quot;&quot;[your app name]&quot;&quot; app on&lt;br /&gt;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;()) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATTIME&quot;&gt;FORMATTIME&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOW&quot;&gt;NOW&lt;/span&gt;()) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, courtesy of Calcapp.&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;This report has been sent from the &quot;&quot;[your app name]&quot;&quot; app on&lt;br /&gt;&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TODAY&quot;&gt;TODAY&lt;/span&gt;()) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;FORMATTIME&quot;&gt;FORMATTIME&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;NOW&quot;&gt;NOW&lt;/span&gt;()) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, courtesy of Calcapp.&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above uses the new &lt;span class=&quot;link function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;FORMATTIME&quot;&gt;FORMATTIME&lt;/span&gt; functions to include the current date
and time in the report. Writing &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;&quot;&lt;/span&gt; inside of a
text string in a formula generates a single quotation mark.&lt;/p&gt;

&lt;p&gt;If you do make use of any of the properties &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Body&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Prologue&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Epilogue&lt;/code&gt;
and your app is not on a White Label plan, you will find that the “Generated by
Calcapp.” blurb is added to the epilogue — the text that appears after the field
values — automatically.&lt;/p&gt;

&lt;p&gt;In other words, nothing material changes in terms of branding if you don’t use
the new properties. If you do, however, discreet Calcapp branding is added to
your reports.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 16:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/formula-driven-emails.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/formula-driven-emails.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Use a formula to determine what fields to include in a report</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Get full control over your reports. Want to only include fields with values
  greater than five? Just use FILTER. Also, hidden fields can now be left out of
  reports.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Three and a half years ago, we had started to lose count of how many times we
had been asked one particular question: How can I determine what fields to
include in a report?&lt;/p&gt;

&lt;p&gt;Calcapp didn’t provide much in the way of customization in that area: you could
only include all fields of the screen the button was on or all fields of the
app, making for reports with lots of unwanted information. An enterprising user
was kind enough to teach us a pretty compelling workaround, which we set out to
share &lt;a href=&quot;/blog/2018/02/09/reports-custom-fields.html&quot;&gt;in a blog post&lt;/a&gt; back in 2018.&lt;/p&gt;

&lt;p&gt;The technique described in the post simply asks app authors to put their report
buttons on separate screens (configured to only include the fields of that
screen), and then add &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden fields&lt;/a&gt;. These hidden fields use
formulas referencing the fields containing the actual information.&lt;/p&gt;

&lt;p&gt;The end result is a single, lone button on a screen. The downside is that you
can’t really have any real fields on that screen (they would get included in the
report), but the upside is that the button can include an arbitrary set of
fields.&lt;/p&gt;

&lt;h2 id=&quot;the-includedfields-property&quot;&gt;The IncludedFields property&lt;/h2&gt;

&lt;p&gt;With our new release, and a &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;formula engine&lt;/a&gt; that supports
&lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt;, that awkward workaround is no longer necessary. Enter the new
&lt;em&gt;IncludedFields&lt;/em&gt; property of &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;email report buttons&lt;/span&gt; and &lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;IncludedFields&quot;&gt;open report buttons&lt;/span&gt;, which must be set through a formula.&lt;/p&gt;

&lt;p&gt;In order for the formula to be picked up by Calcapp, you must configure your
email or open report button to include fields set through a formula. Choose
&lt;strong&gt;Select fields using formula&lt;/strong&gt; from the drop-down menu in the inspector when
your button is selected, and then on the &lt;strong&gt;fx&lt;/strong&gt; button next to &lt;strong&gt;Included
fields&lt;/strong&gt; to edit the formula:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2021-11-12-reports/included-fields.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2021-11-12-reports/included-fields.png&quot; alt=&quot;Calcapp Creator, editing an IncludedFields formula&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This formula includes &lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field2&lt;/em&gt; and &lt;em&gt;Field3&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field2, Field3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field2; Field3 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Ranges enable a large number of fields to be referenced in a compact way. This
formula includes the fields &lt;em&gt;Field1&lt;/em&gt; and &lt;em&gt;Field5&lt;/em&gt;, as well as all fields that
appear between them:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field5&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field5&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula includes &lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field3&lt;/em&gt; and &lt;em&gt;Field5&lt;/em&gt;, as well as the fields
that appear between &lt;em&gt;Field3&lt;/em&gt; and &lt;em&gt;Field5&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field3:Field5 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field3:Field5 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;You can also include all fields of a screen simply by referencing the screen in
the array, include all fields of your app by referencing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App&lt;/code&gt; object and
conditionally include fields using &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;. You can even reference
all fields of a screen, and only include those whose values are greater than 5
(say) using the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function.&lt;/p&gt;

&lt;p&gt;For more on how to use the &lt;em&gt;IncludedFields&lt;/em&gt; property, including lots of
examples, refer to our newly-expanded property documentation for
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;email report buttons&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;OpenReportButton&quot; name=&quot;IncludedFields&quot;&gt;open report buttons&lt;/span&gt;.&lt;/p&gt;

&lt;h2 id=&quot;other-new-report-features&quot;&gt;Other new report features&lt;/h2&gt;

&lt;p&gt;There are two other new report features that warrant discussion. First, you can
now leave out hidden fields from reports simply by toggling the new &lt;strong&gt;Include
hidden fields&lt;/strong&gt; option. Previously, hidden fields were always included.&lt;/p&gt;

&lt;p&gt;This option affects what fields are included even if a formula is used to
determine the set. In other words, if the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IncludedFields&lt;/code&gt; formula elects to
include &lt;em&gt;Field1&lt;/em&gt;, it won’t actually be included if it is hidden and the
&lt;strong&gt;Include hidden fields&lt;/strong&gt; option is toggled off.&lt;/p&gt;

&lt;p&gt;Second, you can now elect not to present fields belonging to different screens
separately by toggling the &lt;strong&gt;Separate different screens&lt;/strong&gt; option.&lt;/p&gt;

&lt;p&gt;This is the result when fields are separated by screen:&lt;/p&gt;

&lt;figure&gt;
  &lt;table class=&quot;data-table&quot;&gt;
    &lt;tr&gt;
      &lt;td&gt;Screen 1:&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 2&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 3&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Screen 2:&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 4&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 5&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 6&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;
&lt;/figure&gt;

&lt;p&gt;This is the result when fields are not separated by screen:&lt;/p&gt;

&lt;figure&gt;
  &lt;table class=&quot;data-table&quot;&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 2&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 3&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 4&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 5&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 6&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;
&lt;/figure&gt;

&lt;p&gt;By not separating fields by screen, you can produce reports that do not mirror
the structure of your app. If you determine what fields to include using the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IncludedFields&lt;/code&gt; property, the report will reflect exactly the fields you
include in the array, in the exact order they are specified there.&lt;/p&gt;

&lt;p&gt;You can also &lt;a href=&quot;/blog/2021/11/12/csv.html&quot;&gt;customize the CSV files sent through your apps&lt;/a&gt; and &lt;a href=&quot;/blog/2021/11/12/formula-driven-emails.html&quot;&gt;add text
before and after field values using formulas&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 15:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/reports.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/reports.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Decide the next screen with a formula</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Skip straight to the results if the entered data checks out, or collect
  supplemental information otherwise. Stop copying and pasting screens — now you
  can make many screens send the user to the same destination.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Since its inception, Calcapp has allowed you define &lt;a href=&quot;/learn/navigation.html&quot;&gt;a hierarchy of
screens&lt;/a&gt; reachable by your users. List screens enable users to
select an option (&lt;a href=&quot;/blog/2021/11/12/new-names.html&quot;&gt;now known as a navigator&lt;/a&gt;) and be brought forward
to the screen associated with the navigator. Form and text screens enable users
to move forward to a single pre-determined screen by pressing &lt;strong&gt;Next&lt;/strong&gt; in the
upper-right corner.&lt;/p&gt;

&lt;p&gt;Up until now, that hierarchy has been fixed and unchangeable, with no room for
making decisions based on formulas. In particular, it has not been possible for
multiple screens or navigators to send the user to the same screen, where this
screen can take the selection made by the user into account.&lt;/p&gt;

&lt;p&gt;Today, all that changes. A new property, &lt;em&gt;NextScreen&lt;/em&gt;, has been added to
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;form screens&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;TextScreen&quot; name=&quot;NextScreen&quot;&gt;text screens&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;Navigator&quot; name=&quot;NextScreen&quot;&gt;navigators&lt;/span&gt;. (Refer to the links for
detailed documentation.)&lt;/p&gt;

&lt;p&gt;This property enables you to do things like send the user to a warning screen if
the information filled out by the user does not check out. You can also take a
user straight to a results screen if you so choose, or ask for additional
information before sending the user to the results screen, all based on
formulas.&lt;/p&gt;

&lt;p&gt;To send a user to a screen named &lt;em&gt;Screen1&lt;/em&gt;, simply associate the following
formula with a &lt;em&gt;NextScreen&lt;/em&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Screen1&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Screen1&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To send a user to &lt;em&gt;Screen1&lt;/em&gt; if &lt;em&gt;Field1&lt;/em&gt; is valid, and to &lt;em&gt;Screen2&lt;/em&gt; otherwise,
use this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;, Screen1, Screen2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Valid&quot;&gt;Valid&lt;/span&gt;; Screen1; Screen2)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To prevent users from moving forward to the next screen, use the pre-existing
&lt;em&gt;NextScreenAvailable&lt;/em&gt; property of
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;form screens&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;TextScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;text screens&lt;/span&gt;. (It used to be
known as &lt;a href=&quot;/blog/2021/11/12/backward-compatibility.html&quot;&gt;NextPanelAvailable&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;(Returning a &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank value&lt;/span&gt; from a &lt;em&gt;NextScreen&lt;/em&gt; property does
not prevent the user from moving forward. Rather, it makes Calcapp use the
screen which naturally follows the screen, which you have set in Calcapp
Creator.)&lt;/p&gt;

&lt;h2 id=&quot;using-a-drop-down-field-as-a-list-screen&quot;&gt;Using a drop-down field as a list screen&lt;/h2&gt;

&lt;p&gt;Up until now, list screens and drop-down fields have had very little in common.
List screens and their navigators have sent users forward to pre-defined
screens, whereas the selection made from a drop-down field has not had any
influence on the screen shown to the user as they move forward.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;NextScreen&lt;/em&gt; property changes all that. Let’s say you have a text drop-down
field named &lt;em&gt;ScreenSelection&lt;/em&gt; with the options “First screen,” “Second screen”
and “Third screen.” To move the user forward to &lt;em&gt;Screen1&lt;/em&gt; if “First screen” is
selected, to &lt;em&gt;Screen2&lt;/em&gt; if “Second screen” is selected and to &lt;em&gt;Screen3&lt;/em&gt; if “Third
screen” is selected, use this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(ScreenSelection, &quot;First screen&quot;, Screen1, &quot;Second&lt;br /&gt;screen&quot;, Screen2, &quot;Third screen&quot;, Screen3)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(ScreenSelection; &quot;First screen&quot;; Screen1; &quot;Second&lt;br /&gt;screen&quot;; Screen2; &quot;Third screen&quot;; Screen3)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;/blog/2021/11/12/if-switch-ifblank.html&quot;&gt;SWITCH is a new function.&lt;/a&gt;) The &lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;
formula above can also be written with the &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ScreenSelection &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;First screen&quot;, Screen1, ScreenSelection &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Second screen&quot;, Screen2, ScreenSelection &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Third screen&quot;, Screen3)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ScreenSelection &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;First screen&quot;; Screen1; ScreenSelection &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Second screen&quot;; Screen2; ScreenSelection &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Third screen&quot;; Screen3)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;using-a-list-screen-as-a-drop-down-field&quot;&gt;Using a list screen as a drop-down field&lt;/h2&gt;

&lt;p&gt;Sometimes, you don’t want a list screen to determine what screen is shown next,
you want the same screen to be shown regardless of what list screen navigator is
chosen. You then want this screen to take into account the selection made by the
user.&lt;/p&gt;

&lt;p&gt;Achieving the first requirement is easy. Simply associate a formula with the
&lt;span class=&quot;link property&quot; parent-type=&quot;Navigator&quot; name=&quot;NextScreen&quot;&gt;NextScreen&lt;/span&gt; property of all navigators of the list
screen—let’s say it’s named &lt;em&gt;ProductChoice&lt;/em&gt;—and have the formula reference the
same screen, named &lt;em&gt;ResultsScreen&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;ResultsScreen&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;ResultsScreen&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The second requirement asks that we have a way of learning what navigator was
selected. This is achieved using a new read-only property of list screens,
&lt;span class=&quot;link property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;To make the title of the next screen reflect the choice made by the user,
associate this formula with the &lt;span class=&quot;link property&quot; parent-type=&quot;Screen&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt; property of the
screen:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;ProductChoice.&lt;span class=&quot;property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;Navigator&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;ProductChoice,&lt;span class=&quot;property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;Navigator&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt; property of &lt;em&gt;ProductChoice&lt;/em&gt;
returns the navigator the user selected. In turn, this navigator has properties
of its own that we can access, including &lt;span class=&quot;link property&quot; parent-type=&quot;Navigator&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;,
reflecting the label of the navigator. (You can associate a formula with the
&lt;em&gt;Label&lt;/em&gt; property &lt;a href=&quot;/blog/2018/03/06/formula-driven-labels.html&quot;&gt;to determine it dynamically&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;You can use the &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; function to look up a value associated
with the selection made by the user. Consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(ProductChoice.&lt;span class=&quot;property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt;.&lt;span class=&quot;property&quot; parent-type=&quot;Navigator&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;, { &quot;Product A&quot;, &quot;Product B&quot;, &quot;Product C&quot; }, { 10, 20, 30 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(ProductChoice,&lt;span class=&quot;property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt;,&lt;span class=&quot;property&quot; parent-type=&quot;Navigator&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;; { &quot;Product A&quot;; &quot;Product B&quot;; &quot;Product C&quot; }; { 10; 20; 30 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above returns the price of the product represented by the navigator
activated by the user. &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; expects its first parameter to be
the value to find in the array given as the second parameter. If found, the
array element at the same position in the array given as the third parameter is
returned. Here, the value to find is the &lt;span class=&quot;link property&quot; parent-type=&quot;Navigator&quot; name=&quot;Label&quot;&gt;label of the navigator&lt;/span&gt; activated by the user, which is expected to be either “Product
A”, “Product B” or “Product C”.&lt;/p&gt;

&lt;p&gt;This &lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt; formula is equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(ProductChoice.&lt;span class=&quot;property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt;, ProductChoice!ProductA, 10, ProductChoice!ProductB, 20, ProductChoice!ProductC, 30)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(ProductChoice,&lt;span class=&quot;property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt;; ProductChoice!ProductA; 10; ProductChoice!ProductB; 20; ProductChoice!ProductC; 30)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;linking-navigators-to-the-same-screen-versus-copying-and-pasting&quot;&gt;Linking navigators to the same screen versus copying and pasting&lt;/h2&gt;

&lt;p&gt;In the past, many app authors wanted to achieve the effect described above, that
is, multiple navigators all leading to the same screen, with this screen taking
the selection into account. This was achievable by liberal use of &lt;a href=&quot;/blog/2017/06/26/copy-paste.html&quot;&gt;copy and
paste&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If a list screen consisted of 20 navigators, app authors would copy a single
screen and paste it 19 times, associating the copies with the other navigators.
To make these screens reflect the selection made by the user, authors would make
small modifications to each screen copy.&lt;/p&gt;

&lt;p&gt;There are several disadvantages to this approach. From an app author’s
perspective, making changes to the duplicated screens becomes an arduous
process, with each change having to be made multiple times. From Calcapp’s
perspective, having screens (and the screens following them) be duplicated many
times makes apps very large, which may make them &lt;a href=&quot;/blog/2021/11/12/large-apps.html&quot;&gt;run sluggishly or not at
all&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By linking several navigators to the same screen, you reap all the rewards of
copying and pasting screens with none of the disadvantages, provided that the
screens you would have copied and pasted differ little from one another.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 14:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/next-screen.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/next-screen.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Decimal commas in formulas</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Formulas written with decimal commas are now fully supported. Set your
  preference the next time you open Calcapp Creator.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Since we launched the first beta version, Calcapp has only recognized decimal
points (“.”) as decimal separators and commas (“,”) as parameter separators in
formulas. This is in line with how numbers are written in countries like the US,
Britain, Australia, New Zeeland, China, Japan, India and parts of Africa.&lt;/p&gt;

&lt;p&gt;However, most parts of South America and Europe (including Russia), as well as
parts of Africa, use decimal commas, making Calcapp formulas feel foreign in
these countries. We often stress that you can frequently carry over formulas
from spreadsheets to Calcapp simply by &lt;a href=&quot;/blog/2017/06/14/convert.html&quot;&gt;copying and pasting them&lt;/a&gt;, but
this has sadly not worked well for our European and South American customers.&lt;/p&gt;

&lt;p&gt;Apps produced with Calcapp have supported languages other than US English &lt;a href=&quot;/blog/2018/03/06/locales.html&quot;&gt;for
three and a half years now&lt;/a&gt;. Numbers are formatted according to the
language of the app and functions like &lt;span class=&quot;link function&quot; name=&quot;PARSENUMBER&quot;&gt;PARSENUMBER&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt; correctly handle the decimal separator of the
configured language. In other words, apps have handled decimal commas correctly
for years now, but not the app designer.&lt;/p&gt;

&lt;p&gt;Programming languages typically use decimal points exclusively. Spreadsheets,
however, with very few exceptions either allow the decimal separator to be set
manually or follow the conventions of the host operating system. Spreadsheets
that use decimal commas as decimal separators use semicolons (“;”) as parameter
separators instead of commas.&lt;/p&gt;

&lt;p&gt;Ironically, we’re a Swedish business, and decimal commas are exclusively used as
decimal separators here. We’re not only Swedish, though, we’re also software
developers. As programming languages exclusively support decimal points, it
appears that we have grown a little too comfortable with decimal points to
realize that this has been a major pain point our customers have experienced.&lt;/p&gt;

&lt;p&gt;This issue is now finally resolved. Decimal commas are fully supported, and you
will be asked your preference when you sign into Calcapp Creator:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2021-11-12-decimal-separator/dialog.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2021-11-12-decimal-separator/dialog.png&quot; alt=&quot;You get asked your decimal separator preference when you start             Calcapp Creator&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you set your preference to decimal commas and you open an app you previously
authored with decimal points, our server will silently convert all formulas of
the app to use decimal commas (and semicolon separators). This process is fast,
and it is accurate, so you don’t have to worry about it making a hash of your
formulas.&lt;/p&gt;

&lt;p&gt;Calcapp Creator will expect you to use decimal commas in other places too, like
when you write initial values for number fields and when you author the numbers
that are part of a number drop-down field.&lt;/p&gt;

&lt;p&gt;This setting does not affect your apps. In order to make them format numbers
with decimal commas, ensure that your app is set to use &lt;a href=&quot;/blog/2018/03/06/locales.html&quot;&gt;a language that uses a
decimal comma as a decimal separator&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 13:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/decimal-separator.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/decimal-separator.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Dramatically improved documentation for formulas and properties</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  What&apos;s got half a million words? The Lord of the Rings trilogy. And our new
  formula and property documentation, which is now on the web. Thousands of
  formula examples make getting started with all the new features easy.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;When we launched the first beta version &lt;a href=&quot;/blog/2015/12/10/status.html&quot;&gt;in late 2015&lt;/a&gt;,
Calcapp supported 20 functions. To document them, we had a simple window, with
most functions only being afforded a single sentence:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2015-12-10-status/screenshot5.jpg&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2015-12-10-status/screenshot5.jpg&quot; alt=&quot;The very first window documenting Calcapp&apos;s 20 functions&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Calcapp went from supporting 20 functions to 244 functions &lt;a href=&quot;/blog/2016/05/25/244-functions.html&quot;&gt;overnight in
2016&lt;/a&gt;. The old documentation window would not have scaled to that
number of functions, so we introduced the &lt;a href=&quot;/blog/2016/05/26/function-browser.html&quot;&gt;function browser&lt;/a&gt;
(which later evolved into the reference sidebar). While all functions were
documented, the descriptions of how they worked remained as terse as ever, with
no examples.&lt;/p&gt;

&lt;p&gt;Truth be told, we always wanted our formula documentation to equal the best that
spreadsheets offered. We could never justify making that investment with a small
team, though, not when fundamental features like &lt;a href=&quot;/blog/2017/06/26/copy-paste.html&quot;&gt;copy and paste&lt;/a&gt;
remained unimplemented.&lt;/p&gt;

&lt;h2 id=&quot;making-a-case-for-better-documentation&quot;&gt;Making a case for better documentation&lt;/h2&gt;

&lt;p&gt;Back in 2016, &lt;a href=&quot;/blog/2016/05/25/244-functions.html&quot;&gt;when we went from 20 functions to 244 functions&lt;/a&gt;,
the only function that was exclusive to Calcapp was &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;, all
the others were standard spreadsheet functions implemented by most spreadsheets.
We didn’t consider the function library to be the Calcapp function library as
much as we considered it to be simply an implementation of standard spreadsheet
functions.&lt;/p&gt;

&lt;p&gt;Over the years, we started making additions. We didn’t like Excel’s
TEXT function and its convoluted format codes, so we created
&lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;. We needed regular expressions to create
&lt;a href=&quot;/blog/2018/04/06/column-converter.html&quot;&gt;an app&lt;/a&gt; for generating &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt; formulas
in 2018, so we adopted Google Sheets functions like &lt;span class=&quot;link function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;
and &lt;span class=&quot;link function&quot; name=&quot;REGEXREPLACE&quot;&gt;REGEXREPLACE&lt;/span&gt; and added our own extensions.&lt;/p&gt;

&lt;p&gt;Of the &lt;a href=&quot;/blog/2021/11/12/new-functions.html&quot;&gt;102 new functions&lt;/a&gt; added with &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;our new
release&lt;/a&gt;, some are exclusive to Calcapp, and others
feature Calcapp extensions we have brought over from traditional programming.
Examples include the formula fragments you can use with functions like
&lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt; and the &lt;a href=&quot;/blog/2021/11/12/enums.html&quot;&gt;enums&lt;/a&gt; you can
use with functions like &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;All that is to say that we have taken ownership of Calcapp’s function library.
We continue to respect the huge investment in time many app authors have made in
learning the standard spreadsheet functions, but we’re not afraid to add
flourishes of our own or reject ideas that we don’t think fit our vision.&lt;/p&gt;

&lt;p&gt;Not all app authors using Calcapp are well-versed in spreadsheet formulas. To
help them get started, and to realize what possibilities a well-thought-out
formula language offers, we need documentation that can stand on its own,
without relying on readers having any prior knowledge of the topic at hand. To
make the documentation easy to digest, we need lots of examples.&lt;/p&gt;

&lt;p&gt;Finally, Calcapp doesn’t just feature functions and operators, it also features
a wholly-original set of properties which can be used to do everything from
setting the &lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;Recipients&quot;&gt;recipients&lt;/span&gt; of a report
to &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;what screen the user is brought to&lt;/span&gt; when
moving on to the next screen. Properties most definitely need great
documentation, because it isn’t to be found anywhere else.&lt;/p&gt;

&lt;p&gt;All of that is to say that we decided to invest many months of work into writing
better documentation because we couldn’t see another way.&lt;/p&gt;

&lt;h2 id=&quot;the-new-documentation&quot;&gt;The new documentation&lt;/h2&gt;

&lt;p&gt;Our new documentation consists of thousands of formula examples and around half
a million words, which is equivalent to the entire Lord of the Rings trilogy.
(Granted, the trilogy is not as repetitive as our documentation for
&lt;span class=&quot;link function&quot; name=&quot;SUMIF&quot;&gt;SUMIF&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;AVERAGEIF&quot;&gt;AVERAGEIF&lt;/span&gt; and friends, which are all
based on the same template.)&lt;/p&gt;

&lt;p&gt;The documentation has moved from the reference sidebar to the web. The reference
sidebar was much too narrow to give us the room we needed for the new
documentation. Also, by moving it to the web, it is much easier to print, and
much easier for search engines to discover and index. (If we’re lucky,
spreadsheet users will find our documentation through search engines, gain value
from it and learn of our existence.)&lt;/p&gt;

&lt;p&gt;Without further ado, &lt;a href=&quot;/learn/formulas/&quot;&gt;here’s our formula documentation&lt;/a&gt;
(encompassing functions and operators) and &lt;a href=&quot;/learn/properties/&quot;&gt;here’s our property
documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We have de-emphasized the “formal parts” of the documentation, including notes
on the parameters to functions, operands to operators as well as return values.
It’s still there (and has often been expanded) — just press &lt;strong&gt;Details&lt;/strong&gt; to get
access to it.&lt;/p&gt;

&lt;p&gt;All formulas exist in two versions, one written with decimal points and one
written with decimal commas. Press the button next to all formulas, labeled with
a decimal point and a decimal comma, to switch between the two variants. The
button next to it copies the formula to the clipboard, enabling you to easily
paste it into the formula field in Calcapp Creator.&lt;/p&gt;

&lt;p&gt;This documentation has been written by our core development team, which is the
same team who answers all your support questions. As a result, we are very much
aware of the problems app authors have encountered while using Calcapp, and we
have tried to clear up as many formula misconceptions as possible through
copious examples.&lt;/p&gt;

&lt;p&gt;Some functions come with lengthy documentation and lots of examples — for
instance, a hard copy of the documentation for &lt;span class=&quot;link function&quot; name=&quot;REDUCE&quot;&gt;REDUCE&lt;/span&gt; would fill
13 pages. Other functions, like the specialized &lt;span class=&quot;link function&quot; name=&quot;LOGNORM.INV&quot;&gt;LOGNORM.INV&lt;/span&gt;,
come with documentation that is every bit as terse as it was in 2016. This
mainly reflects a lack of domain expertise on our part.&lt;/p&gt;

&lt;p&gt;If you need to use a function where you find the documentation lacking, please
&lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;write us&lt;/a&gt;, and we’ll be sure to prioritize it for the next round of
improvements to the documentation.&lt;/p&gt;

&lt;h2 id=&quot;behind-the-scenes&quot;&gt;Behind the scenes&lt;/h2&gt;

&lt;p&gt;Our efforts to modernize and expand our documentation has not just involved
writing, it has also been an engineering effort. Notably, we developed something
close to a CMS (a Content Management System — like a plain text version of
WordPress) to make the writing process as enjoyable as possible.&lt;/p&gt;

&lt;p&gt;Our CMS has close technical ties to Calcapp proper, to ensure that all the
thousands of formulas in the documentation are correct, meaning that we know for
a fact that they won’t emit any errors if you copy and paste them into Calcapp
Creator. (Provided that all referenced fields and other elements are present, of
course.)&lt;/p&gt;

&lt;p&gt;(A bonus to having deep technical ties to Calcapp proper is that we can write
formulas once, using decimal points, and have the version using decimal commas
generated automatically, using the same system that is used for converting your
formulas from one decimal separator to the other when you &lt;a href=&quot;/blog/2021/11/12/decimal-separator.html&quot;&gt;change that
preference&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Those technical ties weren’t always in place. The bulk of the documentation was
written before we realized that we needed to invest time in that engineering
effort. Once those ties were in place, we had to spend weeks sorting out all our
formula blunders. Yes, we make lots of mistakes when writing formulas too — and
we’re the ones who wrote the entirety of Calcapp.&lt;/p&gt;

&lt;p&gt;Just because a formula doesn’t emit any errors in Calcapp Creator doesn’t mean
that it’s correct. A computer scientist would say that a syntactically correct
formula isn’t necessarily semantically correct, meaning that it doesn’t
necessarily do what we need it to do.&lt;/p&gt;

&lt;p&gt;Testing thousands of formulas manually, through copy and paste, wasn’t an
enticing prospect, so we put on our engineering hats once more. We wrote a
program that took our documentation and generated an app for Calcapp, containing
the documentation in its entirety, including not only all formulas but also
&lt;em&gt;their results&lt;/em&gt;, when calculated through Calcapp.&lt;/p&gt;

&lt;p&gt;Our program essentially generated tens of thousands of text fields with multiple
lines whose formulas read something like this:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;Returns whether a text string ends with another text string.&lt;br /&gt;ENDSWITH(&quot;&quot;support@calcapp.net&quot;&quot;, &quot;&quot;@calcapp.net&quot;&quot;) [&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;ENDSWITH&quot;&gt;ENDSWITH&lt;/span&gt;(&quot;support@calcapp.net&quot;, &quot;@calcapp.net&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;] returns TRUE, as&lt;br /&gt;&quot;&quot;support@calcapp.net&quot;&quot; ends with &quot;&quot;@calcapp.net&quot;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;Returns whether a text string ends with another text string.&lt;br /&gt;ENDSWITH(&quot;&quot;support@calcapp.net&quot;&quot;, &quot;&quot;@calcapp.net&quot;&quot;) [&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;ENDSWITH&quot;&gt;ENDSWITH&lt;/span&gt;(&quot;support@calcapp.net&quot;; &quot;@calcapp.net&quot;) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;] returns TRUE, as&lt;br /&gt;&quot;&quot;support@calcapp.net&quot;&quot; ends with &quot;&quot;@calcapp.net&quot;&quot;.&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Essentially, we got an app containing all formulas immediately followed by the
result of evaluating said formula in brackets. The formula above generates the
following output in the app:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Returns whether a text string ends with another text string.
ENDSWITH(&quot;support@calcapp.net&quot;, &quot;@calcapp.net&quot;) [TRUE] returns TRUE, as
&quot;support@calcapp.net&quot; ends with &quot;@calcapp.net&quot;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Still, checking this app to ensure that all formulas returned the expected
results took weeks. It helped us catch and fix hundreds of errors, not just
formula errors in the documentation — and there were plenty of those — but in
Calcapp itself. The part of Calcapp that implements our function library already
had thousands of automated tests prior to our documentation effort, but those
weren’t enough to fully stamp out all bugs. Thanks to this work, our function
library is of higher quality.&lt;/p&gt;

&lt;p&gt;We think we can be reasonably confident that our documentation is mostly
correct. If you find any errors — in terms of formulas or in terms of grammar —
&lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;we want to hear from you&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the new tools we built, we are looking forward to documenting all the new
properties and functions we are planning for future versions.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 12:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/documentation.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/documentation.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: IF without all the parentheses, SWITCH and IFBLANK</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Use the IF function with multiple conditions without having to use more than
  two parentheses. Use SWITCH when you need to test the same value for equality
  against other values.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Using multiple conditions with the &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; function has traditionally
required writing lots of parentheses. Here’s a formula which returns 10 if the
value of &lt;em&gt;Field1&lt;/em&gt; is 1, 20 if it is 2, 30 if it is 3 and 99 otherwise:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1, 10, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 2, 20, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3, 30, 99)))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1; 10; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 2; 20; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3; 30; 99)))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you need a large number of conditions, you need to write a great many end
parentheses, which gets old fast.&lt;/p&gt;

&lt;p&gt;Microsoft introduced the &lt;span class=&quot;link function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt; function a few years ago, which
only requires two parentheses. You’ll be happy to know that we now fully support
this function.&lt;/p&gt;

&lt;p&gt;This IFS formula is equivalent to the formula above:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1, 10, Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 2, 20, Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3, 30, TRUE, 99)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1; 10; Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 2; 20; Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3; 30; TRUE; 99)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;IFS doesn’t have true support for a fallback value, meaning that you need to use
the condition TRUE to include a fallback value.&lt;/p&gt;

&lt;p&gt;We wanted to have full support for a fallback value, and we saw no need to use a
separate function to do so. We simply extended IF, meaning that this formula
works just as well:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1, 10, Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 2, 20, Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3, 30, 99)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 1; 10; Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 2; 20; Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; 3; 30; 99)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We consider &lt;span class=&quot;link function&quot; name=&quot;IFS&quot;&gt;IFS&lt;/span&gt; to be a compatibility function. If you copy and
paste formulas straight from Excel or need to copy formulas from Calcapp to
Excel, by all means, use it. If not, we recommend that you stick with
&lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; and simply leave out all the extra parentheses.&lt;/p&gt;

&lt;h2 id=&quot;switch&quot;&gt;SWITCH&lt;/h2&gt;

&lt;p&gt;When Microsoft introduced IFS, they also introduced &lt;span class=&quot;link function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;,
which is perfect when you need to test the same value for equality against other
values. Here is a formula using SWITCH, which is equivalent to the other
formulas above:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(Field1, 1, 10, 2, 20, 3, 30, 99)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SWITCH&quot;&gt;SWITCH&lt;/span&gt;(Field1; 1; 10; 2; 20; 3; 30; 99)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Finally, don’t forget about &lt;span class=&quot;link function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;, which we &lt;a href=&quot;/blog/2018/04/06/choose.html&quot;&gt;have supported
since 2018&lt;/a&gt;. If you only need to test for equality against a sequence of
numbers starting with 1 (2, 3, 4, …), CHOOSE is perfect.&lt;/p&gt;

&lt;p&gt;CHOOSE has no support for a fallback value, but this formula is in all other
respects identical to the others on this page:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(Field1, 10, 20, 30)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;CHOOSE&quot;&gt;CHOOSE&lt;/span&gt;(Field1; 10; 20; 30)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We added support for CHOOSE partly to enable drop-down field values to easily
map to table values. We wrote &lt;a href=&quot;/blog/2018/04/06/column-converter.html&quot;&gt;an app&lt;/a&gt; to generate CHOOSE
formulas from table data. &lt;a href=&quot;/blog/2018/04/06/choose.html&quot;&gt;That technique&lt;/a&gt; still works well, but you can
also use the new &lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;XLOOKUP&lt;/a&gt; function along with &lt;a href=&quot;/blog/2021/11/12/xlookup-generator.html&quot;&gt;a new app we
wrote&lt;/a&gt; to do the conversion.&lt;/p&gt;

&lt;h2 id=&quot;ifblank&quot;&gt;IFBLANK&lt;/h2&gt;

&lt;p&gt;Spreadsheets provide a number of convenient functions for working with values
which may be errors. &lt;span class=&quot;link function&quot; name=&quot;ISERROR&quot;&gt;ISERROR&lt;/span&gt; is a straight-forward function
which returns whether a value is an error.&lt;/p&gt;

&lt;p&gt;This formula returns TRUE, as numbers cannot be divided by zero:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISERROR&quot;&gt;ISERROR&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;ISERROR&quot;&gt;ISERROR&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If you want to hide an error value, by using a different value if there is an
error, using ISERROR is somewhat awkward:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISERROR&quot;&gt;ISERROR&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0), 0, Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;ISERROR&quot;&gt;ISERROR&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0); 0; Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above uses the value derived from dividing the value of &lt;em&gt;Field1&lt;/em&gt; by
zero, but only if it doesn’t lead to an error. (Obviously, this example is just
for illustrative purposes, as we know for a fact that dividing a number by zero
will always produce an error, so there’s no need to check.)&lt;/p&gt;

&lt;p&gt;You’ll note that we need to repeat the calculation in the formula above. We
could introduce a &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden field&lt;/a&gt; to avoid this, but using
&lt;span class=&quot;link function&quot; name=&quot;IFERROR&quot;&gt;IFERROR&lt;/span&gt; is even better:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IFERROR&quot;&gt;IFERROR&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0, 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IFERROR&quot;&gt;IFERROR&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;DIVISION&quot;&gt;/&lt;/span&gt; 0; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above is fully equivalent to the IF formula above — and a lot
shorter.&lt;/p&gt;

&lt;p&gt;We liked using IFERROR so much that we wanted a version that would do for blank
values what IFERROR does for errors. Enter &lt;span class=&quot;link function&quot; name=&quot;IFBLANK&quot;&gt;IFBLANK&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Just like the name suggests, IFBLANK returns the first parameter unchanged if it
is not blank, and returns the second parameter otherwise:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IFBLANK&quot;&gt;IFBLANK&lt;/span&gt;(Field1, 10)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IFBLANK&quot;&gt;IFBLANK&lt;/span&gt;(Field1; 10)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Normally, operators like &lt;span class=&quot;link binaryOperator&quot; name=&quot;+&quot;&gt;+&lt;/span&gt; treat blank values as though they
were the value 0. With IFBLANK, we can easily change that behavior, and make a
blank value appear as though it was the value 10, with one easy-to-use function.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 11:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/if-switch-ifblank.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/if-switch-ifblank.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: More options for CSV and TSV files</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  CSV files produced by report buttons can now be customized to make them
  compatible with more apps and services. Change the decimal separator and the
  delimiter separating values and lay out values vertically instead of
  horizontally.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Calcapp offers a variety of formats for you to choose between when sharing field
values through email or direct download buttons. One of the most useful formats
is CSV, which stands for Comma-Separated Values, which we introduced
&lt;a href=&quot;/blog/2016/10/18/reporting-email.html&quot;&gt;back in 2016&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;CSV files are just what the name implies—a number of values separated by commas:&lt;/p&gt;

&lt;pre&gt;
  &quot;Screen 1:&quot;
  &quot;Field 1&quot;,&quot;Field 2&quot;,&quot;Field 3&quot;
  1,2,3
  &quot;Screen 2:&quot;
  &quot;Field 4&quot;,&quot;Field 5&quot;,&quot;Field 6&quot;
  4,5,6
&lt;/pre&gt;

&lt;p&gt;This simplicity means that an abundance of tools can import data from CSV files,
including spreadsheets like Microsoft Excel and databases.&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no real CSV standard, meaning that some tools can have
trouble working with the CSV data sent from your apps. When we introduced CSV
support, our main goal was to enable Microsoft Excel to easily import data sent
from your apps. Since then, we have realized that our customers use a variety of
tools to work with our CSV files, which does not always go smoothly. With our
new &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;release&lt;/a&gt;, our goal is to solve these issues.&lt;/p&gt;

&lt;p&gt;When you add a new report button and instruct it to use the CSV format, there is
a new section in the inspector with all the new options:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2021-11-12-csv/inspector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2021-11-12-csv/inspector.png&quot; alt=&quot;The inspector, showing the new CSV and TSV options&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;setting-the-delimiter-and-decimal-separator&quot;&gt;Setting the delimiter and decimal separator&lt;/h2&gt;

&lt;p&gt;The delimiter is the character that separates values in the CSV file. Before
this release, Calcapp always used a comma.&lt;/p&gt;

&lt;p&gt;You can now set the delimiter to a tab character, in which case the resulting
CSV files are often known as TSV files (short for Tab-Separated Values). We have
learned that some apps and services can only work with TSV files, and not CSV
files, which means that these apps and services can now finally work directly
with TSV files produced directly from your apps. You also have the option of
using a space character as a delimiter.&lt;/p&gt;

&lt;p&gt;Software used outside of the English-speaking world often uses a semicolon to
separate fields. The reason is that they typically use a decimal comma as a
decimal separator, and not a decimal point. You can now explicitly set the
delimiter to a semicolon.&lt;/p&gt;

&lt;p&gt;Microsoft Excel uses the language settings of the host operating system to
determine how to handle CSV files. That means that a CSV file produced by Excel
in Germany (which uses a decimal comma as a decimal separator and a semicolon as
a delimiter) may not be readable by a US English version of Excel (at least not
without using the &lt;a href=&quot;https://support.microsoft.com/en-us/office/split-text-into-different-columns-with-the-convert-text-to-columns-wizard-30b14928-5550-41f5-97ca-7a3e9c363ed7&quot;&gt;Data &amp;gt; Text to Columns&lt;/a&gt; feature). That
means that you must often be conscious of what software is used to read your CSV
files, and the language settings used by these users.&lt;/p&gt;

&lt;p&gt;Before this release, Calcapp always used a decimal point as a decimal separator,
regardless of the language your app was configured to use. If Excel was
configured to use a decimal comma, these values would be interpreted as text
strings and not as numbers. Now, you can set the decimal separator explicitly.&lt;/p&gt;

&lt;p&gt;CSV files can use a comma as both a delimiter and as a decimal separator. If you
go that route, though, decimal numbers will be surrounded by quotes in the CSV
file, which increases the file size.&lt;/p&gt;

&lt;h2 id=&quot;the-default-delimiter-and-decimal-separator&quot;&gt;The default delimiter and decimal separator&lt;/h2&gt;

&lt;p&gt;When you create a new email report button or download report button, you will
find that both the delimiter and decimal separator are set to special values
known as &lt;em&gt;Default&lt;/em&gt;. When default values are used, the actual values used depend
on the language settings of your app.&lt;/p&gt;

&lt;p&gt;If the decimal separator is set to the default value, it follows the decimal
separator used by the language the app is configured to use (a decimal comma for
an app in German and a decimal point for an app in English, for instance).&lt;/p&gt;

&lt;p&gt;If the delimiter is set to the default value, a semicolon is used if the
configured decimal separator is a decimal comma. Otherwise, a comma is used.&lt;/p&gt;

&lt;p&gt;We think that these default settings will produce the desired result for most
users. Apps in German tend to produce CSV files which will be consumed by users
using German language settings. With the new defaults, that scenario—and many
like it—will hopefully just work.&lt;/p&gt;

&lt;p&gt;Of course, if your app is in German, but files are sent to headquarters in the
UK, you can manually set the decimal separator and delimiter to values which
will work in the UK.&lt;/p&gt;

&lt;p&gt;Existing apps created by older versions of Calcapp will continue to behave like
before. In other words, they will continue to use a decimal point for a decimal
separator and a comma as a delimiter, regardless of the language settings of the
app. This behavior ensures that our new release does not break existing apps. If
you want to change the behavior,    simply make the desired changes in Calcapp
Creator.&lt;/p&gt;

&lt;h2 id=&quot;excluding-the-delimiter-line&quot;&gt;Excluding the delimiter line&lt;/h2&gt;

&lt;p&gt;There is a new option to “exclude the delimiter line.” Older versions of Calcapp
always included this line as the first line in a CSV file.&lt;/p&gt;

&lt;p&gt;The delimiter line simply specifies what delimiter is used:&lt;/p&gt;

&lt;pre&gt;
  sep=;
  &quot;Screen 1:&quot;
  &quot;Field 1&quot;;&quot;Field 2&quot;;&quot;Field 3&quot;
  1;2;3
  &quot;Screen 2:&quot;
  &quot;Field 4&quot;;&quot;Field 5&quot;;&quot;Field 6&quot;
  4;5;6
&lt;/pre&gt;

&lt;p&gt;Microsoft Excel uses it to correctly read CSV files, regardless of the language
settings used by the host operating system. In other words, CSV files produced
by previous versions of Calcapp were readable even by versions of Excel normally
expecting a semicolon to be used as the delimiter.&lt;/p&gt;

&lt;p&gt;(Unfortunately, there is no “decimal separator line” which can be used to
instruct Excel what decimal separator is used. That means that decimal numbers
in CSV files produced by older versions of Calcapp were likely read as text by
Excel if the host operating system was configured to use a decimal comma as the
decimal separator.)&lt;/p&gt;

&lt;p&gt;Only Excel is known to recognize the delimiter line. If you import a CSV file
into Google Sheets, for instance, it will show up as part of your data.&lt;/p&gt;

&lt;p&gt;For that reason, excluding the delimiter line if Excel is not used to consume
the file is the right course of action. You can also safely exclude it if Excel
is used and you know that it is configured to use the same delimiter that your
CSV files contain.&lt;/p&gt;

&lt;p&gt;Finally, excluding the delimiter line often makes the resulting CSV files much
smaller. The reason is that Calcapp can use &lt;a href=&quot;https://en.wikipedia.org/wiki/UTF-8&quot;&gt;a more space-efficient character
encoding&lt;/a&gt; for the file if a delimiter line is not used than
&lt;a href=&quot;https://en.wikipedia.org/wiki/UTF-16&quot;&gt;the character encoding which would otherwise have been used&lt;/a&gt;,
because of long-standing issues with Microsoft Excel.&lt;/p&gt;

&lt;h2 id=&quot;laying-out-fields-values-horizontally-or-vertically&quot;&gt;Laying out fields values horizontally or vertically&lt;/h2&gt;

&lt;p&gt;Since its inception, Calcapp has laid out fields and their values horizontally.
Consider an app with two screens, &lt;em&gt;Screen1&lt;/em&gt; and &lt;em&gt;Screen2&lt;/em&gt;, each containing three
fields. Here’s the output when values are laid out horizontally, if all fields
are included:&lt;/p&gt;

&lt;figure&gt;
  &lt;table class=&quot;data-table&quot;&gt;
    &lt;tr&gt;
      &lt;td&gt;Screen 1:&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 1&lt;/td&gt;
      &lt;td&gt;Field 2&lt;/td&gt;
      &lt;td&gt;Field 3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Screen 2:&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 4&lt;/td&gt;
      &lt;td&gt;Field 5&lt;/td&gt;
      &lt;td&gt;Field 6&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;
&lt;/figure&gt;

&lt;p&gt;To instead lay out values vertically, choose &lt;strong&gt;Arrange values from top to
bottom&lt;/strong&gt; in the inspector. This is the result:&lt;/p&gt;

&lt;figure&gt;
  &lt;table class=&quot;data-table&quot;&gt;
    &lt;tr&gt;
      &lt;td&gt;Screen 1:&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 2&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 3&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Screen 2:&lt;/td&gt;
      &lt;td&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 4&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 5&lt;/td&gt;
      &lt;td&gt;5&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Field 6&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;
&lt;/figure&gt;

&lt;p&gt;When you create a new button, values are laid out vertically by default.
However, apps created with older versions of Calcapp will continue to lay out
values horizontally until you change the option in Calcapp Creator.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 10:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/csv.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/csv.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: More customizable reset buttons</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Use a formula to determine which fields are reset by a reset button. These
  buttons can now assign blank values to fields.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Reset buttons were added to Calcapp &lt;a href=&quot;/blog/2016/10/17/reset-fields.html&quot;&gt;years ago&lt;/a&gt; and have changed
little since. You have been limited to either resetting all fields of the
current screen or resetting all fields of the app. Also, resetting a field has
always meant restoring its value to its &lt;a href=&quot;/blog/2017/08/14/initial-value.html&quot;&gt;initial value&lt;/a&gt;, never to
a blank value.&lt;/p&gt;

&lt;p&gt;Today, reset buttons finally become more customizable.&lt;/p&gt;

&lt;h2 id=&quot;the-includedfields-property&quot;&gt;The IncludedFields property&lt;/h2&gt;

&lt;p&gt;Like &lt;a href=&quot;/blog/2021/11/12/reports.html&quot;&gt;email and download buttons&lt;/a&gt;, reset buttons now support the
&lt;span class=&quot;link property&quot; parent-type=&quot;ResetButton&quot; name=&quot;IncludedFields&quot;&gt;IncludedFields&lt;/span&gt; property, which you can set through a
formula. For a reset button, this property determines which fields to reset.&lt;/p&gt;

&lt;p&gt;In order for the formula to be picked up by Calcapp, you must configure your
button to determine what fields to reset using a formula. Choose &lt;strong&gt;Select fields
using formula&lt;/strong&gt; from the drop-down menu in the inspector when your button is
selected, and then on the &lt;strong&gt;fx&lt;/strong&gt; button next to &lt;strong&gt;Included fields&lt;/strong&gt; to edit the
formula:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2021-11-12-reset-buttons/inspector.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2021-11-12-reset-buttons/inspector.png&quot; alt=&quot;The inspector, showing the options for reset buttons&quot; class=&quot;small-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For instance, to reset &lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field2&lt;/em&gt; and &lt;em&gt;Field3&lt;/em&gt;, associate the following
formula with the &lt;em&gt;IncludedFields&lt;/em&gt; property:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field2, Field3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field2; Field3 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Ranges enable a large number of fields to be referenced in a compact way. This
formula resets the fields &lt;em&gt;Field1&lt;/em&gt; and &lt;em&gt;Field5&lt;/em&gt;, as well as all fields that
appear between them:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field5&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field5&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula resets &lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field3&lt;/em&gt; and &lt;em&gt;Field5&lt;/em&gt;, as well as the fields that
appear between &lt;em&gt;Field3&lt;/em&gt; and &lt;em&gt;Field5&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field3:Field5 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field3:Field5 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;You can also reset all fields of a screen simply by referencing the screen in
the array, reset all fields of your app by referencing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;App&lt;/code&gt; object and
conditionally reset fields using &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;. You can even reference all
fields of a screen, and only reset those whose values are greater than 5 (say)
using the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function.&lt;/p&gt;

&lt;p&gt;For more on how to use the &lt;em&gt;IncludedFields&lt;/em&gt; property, including lots of
examples, refer to our &lt;span class=&quot;link property&quot; parent-type=&quot;ResetButton&quot; name=&quot;IncludedFields&quot;&gt;newly-expanded property documentation&lt;/span&gt;.&lt;/p&gt;

&lt;h2 id=&quot;resetting-fields-to-blank-values&quot;&gt;Resetting fields to blank values&lt;/h2&gt;

&lt;p&gt;What does it mean to reset a field? Up until today, it has meant setting its
value to the same value the field had when it was first shown. If no initial
value has been assigned, that is a &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank value&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Many app authors found it puzzling to see the value revert to a prior value when
the field was reset, though. Instead, they expected fields to lose their values,
that is, be assigned blank values.&lt;/p&gt;

&lt;p&gt;That behavior can now be realized by selecting &lt;strong&gt;Assign blank value&lt;/strong&gt; in the
inspector. The default remains &lt;strong&gt;Assign initial value&lt;/strong&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 09:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/reset-buttons.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/reset-buttons.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Download and start large apps faster</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Many under-the-hood improvements make large apps download and start faster and
  consume less space when stored for offline use.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Making Calcapp perform better with very large apps has been an ongoing project
for us for several years now. In 2018, we started &lt;a href=&quot;/blog/2018/02/19/faster-loading.html&quot;&gt;compressing apps sent from
our server&lt;/a&gt;. Later that year, we made &lt;a href=&quot;/blog/2018/07/29/performance.html&quot;&gt;navigating such apps
much faster&lt;/a&gt; and improved the way our server responds to app
requests. In 2019, we responded to an influx of users by &lt;a href=&quot;/blog/2019/01/16/stability.html&quot;&gt;tripling the memory
available to our server&lt;/a&gt;, making very large apps run much better.&lt;/p&gt;

&lt;p&gt;Our new release further improves our handling of very large apps. When users
download such apps, they will find that they download much faster.&lt;/p&gt;

&lt;p&gt;For small apps, you probably won’t notice much difference. For very large apps,
however, the savings can be huge. We managed to shrink one app from 158 MB to 30
MB (or from 8.9 MB to 1.7 MB with &lt;a href=&quot;/blog/2018/02/19/faster-loading.html&quot;&gt;compression turned on&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Such a large app is not only downloaded faster, it is also processed faster when
it starts. Also, storing it for &lt;a href=&quot;/blog/2020/04/02/offline.html&quot;&gt;offline use&lt;/a&gt; doesn’t consume as much
storage for your users.&lt;/p&gt;

&lt;p&gt;This post is somewhat technical. If you’re not interested in the nitty-gritty,
you can safely skip this material, knowing that large apps now work better.&lt;/p&gt;

&lt;h2 id=&quot;omitting-default-values&quot;&gt;Omitting default values&lt;/h2&gt;

&lt;p&gt;One technique we used to make apps download faster is that we no longer send
“default values.” What that means is that if you add 100 fields to your app, we
used to store all values you set in the inspector, even if you never changed the
defaults, for all 100 fields.&lt;/p&gt;

&lt;p&gt;Number fields are normally formatted with two decimal places, and if you don’t
change that setting, we will no longer send that information when an app is
downloaded — your app will just assume that number fields should be formatted
with two decimal places unless if hears differently.&lt;/p&gt;

&lt;p&gt;It turns out that there are lots of values that app authors rarely change,
meaning that we can leave them out most of the time. This makes for significant
savings.&lt;/p&gt;

&lt;h2 id=&quot;making-information-about-your-app-easily-accessible&quot;&gt;Making information about your app easily accessible&lt;/h2&gt;

&lt;p&gt;There is some information about your apps that our server needs to process very
often. One of the most important pieces of information is what version of
Calcapp is targeted.&lt;/p&gt;

&lt;p&gt;From an app author’s perspective, there are no Calcapp versions, it just
regularly improves. Behind the scenes, though, we make changes all the time. We
make changes to the way your apps are stored in our database and we make changes
to how your apps are represented internally. We even rename properties and
functions from time to time, which necessitates rewriting your formulas (prior
to &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;this release&lt;/a&gt;, for instance, the form screen property
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt; was named &lt;em&gt;NextPanelAvailable&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;In fact, we spend lots of time writing software that you never see, whose only
purpose is to move your apps from one Calcapp version to a more current version,
which we refer to as our “migration process.” We have spent a lot of time
optimizing this process, with a view towards minimizing server downtime. It now
takes roughly 24 hours to migrate all your apps to a new version, but our server
remains available during all that time, except for around ten minutes when you
can’t change any apps (you can still run apps).&lt;/p&gt;

&lt;p&gt;The Calcapp version is really important, and it should be stored in a way that
makes it fast to access. We also need quick access your &lt;a href=&quot;/blog/2021/11/12/decimal-separator.html&quot;&gt;decimal separator
preference&lt;/a&gt; (decimal comma or decimal point?), so that we can
convert all the formulas to your chosen decimal separator when necessary.&lt;/p&gt;

&lt;p&gt;Collectively, all this “meta” information is stored in your app “header.” It’s
supposed to be at the very start of your app (hence the name), but for various
technical reasons, it was sometimes located in the middle, or at the very end of
your app. That meant that for very large apps, our server had to repeatedly
search through hundreds of megabytes of data to locate the information it
needed, making it sluggish.&lt;/p&gt;

&lt;p&gt;Thankfully, we have now fixed this issue, meaning that large apps should no
longer slow down the server in this way.&lt;/p&gt;

&lt;h2 id=&quot;compressing-dependencies&quot;&gt;Compressing dependencies&lt;/h2&gt;

&lt;p&gt;Our server does a lot of heavy lifting behind the scenes to ensure that your
apps run as quickly as possible. One thing it does is that it figures out what
properties depend on one another. Let’s say that the value of &lt;em&gt;Field1&lt;/em&gt; is
defined as follows:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 20&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 20&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;When the value of &lt;em&gt;Field2&lt;/em&gt; changes, your app knows that the value of &lt;em&gt;Field1&lt;/em&gt;
depends on it and that it needs to be re-calculated, but that it can use old
(cached) values for unaffected properties. We say that
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; is a dependency of
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; and that &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; is a
dependent of &lt;span class=&quot;formula decimalpoint&quot;&gt;Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;. This makes your app run much
faster than if it had to re-calculate everything every time anything changed.&lt;/p&gt;

&lt;p&gt;(Have you ever used &lt;a href=&quot;https://exceljet.net/lessons/how-to-trace-formula-relationships&quot;&gt;“trace precedents”&lt;/a&gt; in a spreadsheet? It’s the
same idea.)&lt;/p&gt;

&lt;p&gt;This information used to take up a lot of space. When
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; noted that &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;
depended on it, it used the full name of the screen it belonged to, the full
name of &lt;em&gt;Field1&lt;/em&gt; and the full name of the &lt;em&gt;Value&lt;/em&gt; property. That can take up a
lot of space. Now, we assign numerical identifiers to properties (like “232”)
and just reference those.&lt;/p&gt;

&lt;p&gt;We also stored even indirect dependents (say, if
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field3.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field3,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; depends on &lt;span class=&quot;formula decimalpoint&quot;&gt;Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;,
which depends on &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;,
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; would store both &lt;span class=&quot;formula decimalpoint&quot;&gt;Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;
and &lt;span class=&quot;formula decimalpoint&quot;&gt;Field3.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field3,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; as dependents). For some large apps, a
single key field could have thousands or tens of thousands of indirect
dependents. Just storing the dependents of fields could take up hundreds of
megabytes of storage for particularly large apps, which is data that would need
to be sent and read every time your app was downloaded.&lt;/p&gt;

&lt;p&gt;We now only store direct dependents, meaning that your apps need to do a bit
more work when run, but it’s well worth it to save a lot of space.&lt;/p&gt;

&lt;p&gt;Also, there are a lot of what we call &lt;em&gt;implicit dependencies&lt;/em&gt; between
properties. The &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;FormattedValue&quot;&gt;FormattedValue&lt;/span&gt; property of number
fields has an implicit dependency on the &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;
property, meaning that even if you refer to a formatted value, your formula will
get re-calculated when the value changes.&lt;/p&gt;

&lt;p&gt;These implicit dependencies used to be communicated explicitly by our server.
Now, we don’t do that anymore, because your apps are smart enough to know about
all those implicit dependencies. That also saves a lot of space.&lt;/p&gt;

&lt;p&gt;Finally, we no longer reference properties by name in the JavaScript expressions
that your Calcapp formulas are converted to by our server. Instead we use — you
guessed it — the numerical identifier we now generate. That makes the JavaScript
versions of your formulas a lot shorter too.&lt;/p&gt;

&lt;h2 id=&quot;the-road-ahead-for-large-apps&quot;&gt;The road ahead for large apps&lt;/h2&gt;

&lt;p&gt;We’ve worked hard for years now on improving support for large apps, and we’ll
be the first to admit that we still have a lot of work to do.&lt;/p&gt;

&lt;p&gt;In the past, we used to advertise our White Label plan as supporting arbitrarily
large apps. We no longer do that, because Calcapp can’t handle arbitrarily large
apps. We now advertise our best plan as supporting “up to 5,000 fields.” We
don’t actually enforce that limit — you’re welcome to go over it if you like —
but we can’t in good conscience claim that we do a good job of supporting apps
larger than that.&lt;/p&gt;

&lt;p&gt;We actually do pretty well, compared to other app builders. Microsoft asks that
you don’t add &lt;a href=&quot;https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/performance-tips&quot;&gt;more than 500 controls&lt;/a&gt; to apps
built with PowerApps, for instance.&lt;/p&gt;

&lt;p&gt;We would like to do better, though, and we have a few changes in mind that we
want to make part of our &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;next-generation Calcapp 4 project&lt;/a&gt;. Stay
tuned, we’ll have more to say on this subject in the future.&lt;/p&gt;

&lt;h2 id=&quot;what-you-can-do-to-make-large-apps-run-better-today&quot;&gt;What you can do to make large apps run better today&lt;/h2&gt;

&lt;p&gt;One way to make large apps run better today is to not make them as large — at
least not as perceived by Calcapp. In the past, many app authors have liberally
used &lt;a href=&quot;/blog/2017/06/26/copy-paste.html&quot;&gt;copy and paste&lt;/a&gt; to duplicate screens, where the duplicates
often differ very little from one another.&lt;/p&gt;

&lt;p&gt;There are several disadvantages to this approach. From an author’s perspective,
making changes to the duplicated screens becomes an arduous process, with each
change having to be made multiple times. From Calcapp’s perspective, having
screens be duplicated many times makes apps very large, which may make them run
sluggishly or not at all.&lt;/p&gt;

&lt;p&gt;Fortunately, there is now a better way. The new &lt;em&gt;NextScreen&lt;/em&gt; property of
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreen&quot;&gt;form screens&lt;/span&gt;,
&lt;span class=&quot;link property&quot; parent-type=&quot;TextScreen&quot; name=&quot;NextScreen&quot;&gt;text screens&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;Navigator&quot; name=&quot;NextScreen&quot;&gt;navigators&lt;/span&gt; enables the same screen to be
reachable from many different places. You can even use conditional logic to
determine which screen the user should be taken to.&lt;/p&gt;

&lt;p&gt;If you make a number of list screen navigators all take the user to the same
screen, use the &lt;span class=&quot;link property&quot; parent-type=&quot;ListScreen&quot; name=&quot;ActiveNavigator&quot;&gt;ActiveNavigator&lt;/span&gt; property of list
screens to learn which navigator was selected. You can even plug the label of
the selected navigator into an &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; formula to look up a
value based on the selection.&lt;/p&gt;

&lt;p&gt;To learn more, &lt;a href=&quot;/blog/2021/11/12/next-screen.html&quot;&gt;read our post about the new properties&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 08:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/large-apps.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/large-apps.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Include array elements conditionally with IF</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Use IF to determine if an element should be part of an array.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt; function has special behavior when used inside of
&lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;arrays&lt;/a&gt;. Specifically, if its third parameter is not given, it can be
used to determine if array elements should be part of the array.&lt;/p&gt;

&lt;p&gt;This can be very useful at times. The &lt;span class=&quot;link property&quot; parent-type=&quot;ResetButton&quot; name=&quot;IncludedFields&quot;&gt;IncludedFields&lt;/span&gt;
property of a reset button is used to determine what fields are reset by the
button. This formula makes sure that &lt;em&gt;Field1&lt;/em&gt; is always reset, but &lt;em&gt;Field2&lt;/em&gt; is
only reset if the value of &lt;em&gt;Field1&lt;/em&gt; is greater than 4:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4, Field2) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4; Field2) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In other words, the returned array is &lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1 }&lt;/span&gt; if the value
of &lt;em&gt;Field1&lt;/em&gt; is not greater than 4. Otherwise, the returned array is
&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field2 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field2 }&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Not including the third parameter to IF causes it to return a &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank value&lt;/span&gt;. That means that these formulas are typically equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4, Field2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4; Field2)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4, Field2, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4; Field2; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;However, these formulas are not equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4, Field2) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4; Field2) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4, Field2, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()) }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4; Field2; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()) }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;If the value of &lt;em&gt;Field1&lt;/em&gt; is not greater than 4, the first formula above returns
the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1 }&lt;/span&gt; (without &lt;em&gt;Field2&lt;/em&gt;). However, the second
formula above returns the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() }&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;In other words, when you construct an array and use IF to include elements
conditionally, only set the third parameter to &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt; if you
want a blank value to be part of your array if the condition does not hold. If
you want to leave out the element completely, leave out the third IF parameter.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 07:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/array-if.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/array-if.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Feature: Join arrays together with |</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Use the new operator | to join together arrays with other arrays and values.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;We have a brand new operator for joining together arrays with other arrays and
values: the array concatenation operator &lt;span class=&quot;link binaryOperator&quot; name=&quot;|&quot;&gt;|&lt;/span&gt;. It does for arrays
what the text concatenation operator &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; does for text.&lt;/p&gt;

&lt;p&gt;These formulas all return the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3, 4 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3; 4 }&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 3, 4 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 3; 4 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; 4&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; 4&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 2, 3, 4 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 2; 3; 4 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 2, 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; 4&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; { 2; 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; 4&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Let’s say that you have an email report button (which sends an email with field
values when pressed) and a download report button (which downloads a file
containing field values when pressed). You set the
&lt;span class=&quot;link property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;IncludedFields&lt;/span&gt; property of the email report
button to a complicated formula which includes all the fields you want to email
your user.&lt;/p&gt;

&lt;p&gt;Now, what if you want the download report button to include the same fields, but
also include another one, &lt;em&gt;Field50&lt;/em&gt;? Do you need to copy the original formula
for the email report button and change it for the download report button?&lt;/p&gt;

&lt;p&gt;No, you can simply reference the original array from the download report button
formula and use the &lt;span class=&quot;link binaryOperator&quot; name=&quot;|&quot;&gt;|&lt;/span&gt; operator to add &lt;em&gt;Field50&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;EmailReportButton1.&lt;span class=&quot;property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;IncludedFields&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; Field50&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;EmailReportButton1,&lt;span class=&quot;property&quot; parent-type=&quot;EmailReportButton&quot; name=&quot;IncludedFields&quot;&gt;IncludedFields&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ARRAY_CONCATENATION&quot;&gt;|&lt;/span&gt; Field50&lt;/span&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 12 Nov 2021 06:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/array-concatenation.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/array-concatenation.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Tip: Debug arrays by inspecting their elements</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  If a function isn&apos;t returning the value you expect, you need to look at the
  parameters it receives by creating new temporary fields visualizing the
  parameters. To do so with an array, you need to convert it to a text string
  first using the TEXTJOIN function.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Let’s say that you need the sum of an array, &lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;expressed as a range&lt;/a&gt;.
Let’s also assume that a form screen holds five number fields, &lt;em&gt;Field1&lt;/em&gt;,
&lt;em&gt;Field2&lt;/em&gt;, &lt;em&gt;Field3&lt;/em&gt;, &lt;em&gt;Field4&lt;/em&gt; and &lt;em&gt;Field5&lt;/em&gt;, in that order.&lt;/p&gt;

&lt;p&gt;You write the following formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field5)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt;(Field1:Field5)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The resulting sum isn’t what you expect. What to do?&lt;/p&gt;

&lt;p&gt;If SUM, or any other function, isn’t returning the value you expect, you need to
look at the parameters it receives. Normally, this would be simple — just add
temporary fields to your app with its formulas set to the function parameters
you want to inspect. When you run the app, you get to see their values, which
helps you figure out why the function isn’t returning the result you expect.&lt;/p&gt;

&lt;p&gt;In this case, this is the formula we need to inspect:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field5&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field5&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;When given as a parameter to SUM, the formula above returns an array of numbers.
However, there isn’t (&lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;yet?&lt;/a&gt;) a field which can visualize arrays.&lt;/p&gt;

&lt;p&gt;To solve this, you need to convert the formula to a text string, which enables
you to display the array of numbers using a text field. For this purpose, the
&lt;span class=&quot;link function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt; function is perfect.&lt;/p&gt;

&lt;p&gt;Here’s how to use it to visualize &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field5&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field5&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;, FALSE, Field1:Field5)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;; FALSE; Field1:Field5)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;As its name implies, TEXTJOIN takes an array and converts it to a text string.
To do so, it joins all elements of the array together, separating them with the
first parameter, &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;, &quot;&lt;/span&gt;. The second parameter, FALSE, instructs
TEXTJOIN to include blank values, which is important when we need to visualize
an array.&lt;/p&gt;

&lt;p&gt;The formula above produces a text string like the following, if
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field4.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field4,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; is &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1, 2, 3, , 5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Technically, &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field5&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field5&lt;/span&gt; is an array of number fields.
TEXTJOIN only knows how to process arrays of numbers, logical values, text
strings or colors, so it asks &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field5&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field5&lt;/span&gt; to convert itself
to such an array. Number fields have &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;values&lt;/span&gt;
which are numbers, meaning that the formula above is equivalent to this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;, FALSE, { Field1:Field5 }.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;; FALSE; { Field1:Field5 },&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;While inspecting the actual values is what you want most of the time, you can
also inspect the labels of the fields. Doing so is easy:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;, FALSE, { Field1:Field5 }.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;, &quot;; FALSE; { Field1:Field5 },&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Label&quot;&gt;Label&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above produces a text string like the following:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field 1, Field 2, Field 3, Field 4, Field 5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use this tip whenever you need to inspect what elements an array holds.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 05:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/debug-arrays.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/debug-arrays.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Tip: Avoid gotchas when adding text boxes and buttons in the middle of a range</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Ranges are an effective means of creating arrays containing many elements.
  However, it is easy to lose track of what elements they contain, which can
  have surprising results. This tip explores this topic in depth.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2021/11/12/arrays.html&quot;&gt;Arrays&lt;/a&gt; are arguably the biggest addition to &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;our latest Calcapp
release&lt;/a&gt;. They form a core part of the many &lt;a href=&quot;/blog/2021/11/12/new-functions.html&quot;&gt;new
functions&lt;/a&gt; and properties, and make Calcapp much more powerful.&lt;/p&gt;

&lt;p&gt;However, when used with ranges, it’s easy to lose track of what elements are
actually included in an array. That can have surprising results, which the topic
for this post.&lt;/p&gt;

&lt;h2 id=&quot;blank-values-and-ranges&quot;&gt;Blank values and ranges&lt;/h2&gt;

&lt;p&gt;Consider the following formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;(Field1:Field3)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;(Field1:Field3)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt; multiplies its parameters together and returns the
result. &lt;span class=&quot;link function&quot; name=&quot;SUM&quot;&gt;SUM&lt;/span&gt; is similar, but adds numbers together instead.&lt;/p&gt;

&lt;p&gt;Remember that the range &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3&lt;/span&gt; is equivalent to the
array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field2, Field3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field2; Field3 }&lt;/span&gt;, but only if &lt;em&gt;Field2&lt;/em&gt; is the
only element that appears between &lt;em&gt;Field1&lt;/em&gt; and &lt;em&gt;Field3&lt;/em&gt;. If that is the case,
this formula is equivalent to the one above:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1, Field2, Field3 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1; Field2; Field3 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;What happens if you add a text box, named &lt;em&gt;Instructions&lt;/em&gt;, right underneath
&lt;em&gt;Field1&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;That change affects the &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3&lt;/span&gt; range. Instead of
expanding to the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Field2, Field3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Field2; Field3 }&lt;/span&gt;, it expands
to the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ Field1, Instructions, Field2, Field3 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ Field1; Instructions; Field2; Field3 }&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;In other words, what Calcapp sees is this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1, Instructions, Field2, Field3 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1; Instructions; Field2; Field3 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Calcapp could show an error here, complaining that while &lt;em&gt;Field1&lt;/em&gt;,
&lt;em&gt;Field2&lt;/em&gt; and &lt;em&gt;Field3&lt;/em&gt; can be treated as numbers (through their
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; properties), &lt;em&gt;Instructions&lt;/em&gt;
cannot, and therefore must not be used with PRODUCT.&lt;/p&gt;

&lt;p&gt;Showing an error wouldn’t be helpful, though, because it would mean that
formulas like the one above would break the moment you add a text box or button
in the middle of a range. Thankfully, Calcapp is forgiving when handling arrays,
and no error is shown.&lt;/p&gt;

&lt;p&gt;Instead, &lt;span class=&quot;link function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt; is given an array, consisting of the values of
the fields and a &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank value&lt;/span&gt; for the text box, as
illustrated by this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(), Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;, Field3.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(); Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;; Field3,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;PRODUCT ignores the blank value, and returns the product of the field values,
as expected. Had it not ignored the blank value, and instead treated it as
zero, the returned value would have been zero.&lt;/p&gt;

&lt;p&gt;It would arguably be surprising behavior if adding a text box in the middle of
the &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3&lt;/span&gt; range caused formulas to seemingly
malfunction, so it’s a good thing that PRODUCT ignores blank values.&lt;/p&gt;

&lt;h2 id=&quot;blank-values-are-not-always-ignored&quot;&gt;Blank values are not always ignored&lt;/h2&gt;

&lt;p&gt;So far, everything works the way we expect it to. However, what happens if we
try to add 2 to the elements of an array?&lt;/p&gt;

&lt;p&gt;Consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;(Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;(Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above applies the &lt;span class=&quot;link function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt; function to the array that
results from adding 2 to the &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3&lt;/span&gt; range.&lt;/p&gt;

&lt;p&gt;When the range is expanded, the following equivalent formula is the result:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1, Instructions, Field2, Field3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1; Instructions; Field2; Field3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;When the value to the left of the &lt;span class=&quot;link binaryOperator&quot; name=&quot;+&quot;&gt;+&lt;/span&gt; operator is an array and the
value to its right is a number — which is the case above — the number is added
to each element of the array.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field2&lt;/em&gt; and &lt;em&gt;Field3&lt;/em&gt; are number fields. 2 cannot be added directly to
them, but can be added to their &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; properties.
That causes &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt; to be expanded to
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Instructions&lt;/em&gt; is a text box, though, and it does not have a number property.
That causes Calcapp to replace it with a blank value before adding 2 to it:
&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the fully-expanded formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2, Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2, Field3.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;({ Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2; Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2; Field3,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;() &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;, the &lt;span class=&quot;link binaryOperator&quot; name=&quot;+&quot;&gt;+&lt;/span&gt; operator treats a blank
value as zero, and therefore returns 2. That means that PRODUCT longer ignores
the text box that appears in the array, as the second value passed to PRODUCT is
2 and not a blank value, causing the result to be twice the number you might
expect.&lt;/p&gt;

&lt;p&gt;In other words, if you use a formula like
&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;(Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;PRODUCT&quot;&gt;PRODUCT&lt;/span&gt;(Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2)&lt;/span&gt;, you’ll get different results
depending on if you add a text box or button in the middle of the range. If your
app returns puzzling results and you use ranges, this is important to be aware
of.&lt;/p&gt;

&lt;p&gt;If you are unsure what array elements are included in a range, create a
temporary field whose only purpose is printing the elements of the array. That
is the topic for &lt;a href=&quot;/blog/2021/11/12/debug-arrays.html&quot;&gt;this tip&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;blank-array-elements-and-filter&quot;&gt;Blank array elements and FILTER&lt;/h2&gt;

&lt;p&gt;Blank values in arrays and ranges can also cause surprising results when used
with the &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; function.&lt;/p&gt;

&lt;p&gt;To recap, FILTER accepts an array as its first parameter and returns a version
of this array which only contains elements that have passed a test you have
supplied.&lt;/p&gt;

&lt;p&gt;The most commonly used variant of FILTER expresses this test as a logical array
given as the second parameter, which should contain the same number of elements
as the array to filter. If an element of the second array is TRUE, the
corresponding element of the array to filter is part of the returned array. If
it is FALSE, the element is dropped.&lt;/p&gt;

&lt;p&gt;This formula returns an array of fields whose values are greater than 4:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3, Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3; Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(The &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4&lt;/span&gt; formula fragment returns the logical
array expected by FILTER. Consult our documentation for the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;gt;&quot;&gt;&amp;gt;&lt;/span&gt;
operator to learn more.)&lt;/p&gt;

&lt;p&gt;The formula above expands to this formula, if &lt;em&gt;Field3&lt;/em&gt; directly follows
&lt;em&gt;Field2&lt;/em&gt;, which directly follows &lt;em&gt;Field1&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ Field1, Field2, Field3 }, { Field1, Field2, Field3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ Field1; Field2; Field3 }; { Field1; Field2; Field3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s once more consider what happens when the text box
&lt;em&gt;Instructions&lt;/em&gt; appears just below &lt;em&gt;Field1&lt;/em&gt;. If that is the case, the first
formula of this section — using the range &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3&lt;/span&gt; —
is equivalent to this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ Field1, Instructions, Field2, Field3 }, { Field1, Instructions, Field2, Field3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ Field1; Instructions; Field2; Field3 }; { Field1; Instructions; Field2; Field3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;gt;&quot;&gt;&amp;gt;&lt;/span&gt; operator can only work with numbers, logical
values, text strings and colors. The number fields can return their
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;values&lt;/span&gt; to satisfy these requirements,
but &lt;em&gt;Instructions&lt;/em&gt; is a text box and cannot do the same. As a result, it
is replaced by a blank value.&lt;/p&gt;

&lt;p&gt;The formula above expands to this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ Field1, Instructions, Field2, Field3 }, { Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;, &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(), Field2.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;, Field3.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ Field1; Instructions; Field2; Field3 }; { Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;; &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(); Field2,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;; Field3,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt; } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In other words, the first element of the array to filter — &lt;em&gt;Field1&lt;/em&gt; — is only
kept if &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;Value&lt;/span&gt;&lt;/span&gt; is greater than 4, and likewise for the
other fields. The second element of the array to filter — &lt;em&gt;Instructions&lt;/em&gt; —
is only kept if &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;()&lt;/span&gt; is greater than 4 (which it is not,
as the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;gt;&quot;&gt;&amp;gt;&lt;/span&gt; operator treats a blank value as zero).&lt;/p&gt;

&lt;p&gt;Therefore, somewhat counter-intuitively, &lt;em&gt;Instructions&lt;/em&gt; is not part of the
returned array because it is not considered to be greater than 4. Had the
condition been &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 4&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;binaryOperator&quot; name=&quot;LESS_THAN&quot;&gt;&amp;lt;&lt;/span&gt; 4&lt;/span&gt; instead, it would have been
included, as the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;lt;&quot;&gt;&amp;lt;&lt;/span&gt; operator would have treated it as the value
zero.&lt;/p&gt;

&lt;h2 id=&quot;filter-used-with-formula-fragments-works-differently&quot;&gt;FILTER used with formula fragments works differently&lt;/h2&gt;

&lt;p&gt;There is a variant of &lt;span class=&quot;link function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt; that doesn’t take a logical array
as its second parameter, but a formula fragment. This fragment is invoked once
per array element, with the element under consideration available as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Element&lt;/code&gt;,
and is expected to return TRUE if the element should be included and FALSE
otherwise.&lt;/p&gt;

&lt;p&gt;These two formulas are equivalent if the &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3&lt;/span&gt; range
only contains number fields:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3, Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3; Field1:Field3 &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3, Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;(Field1:Field3; Element &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN&quot;&gt;&amp;gt;&lt;/span&gt; 4)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(The version using a formula fragment is a Calcapp extension. It has more in
common with JavaScript’s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter&quot;&gt;filter() function&lt;/a&gt; than with
Excel’s FILTER function.)&lt;/p&gt;

&lt;p&gt;However, if the &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1:Field3&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1:Field3&lt;/span&gt; range also includes a text box,
the first formula above will work, but you will get an error message from the
second version in Calcapp Creator, preventing you from sharing your app. The
reason is that formula fragments are more strict than arrays.&lt;/p&gt;

&lt;p&gt;To get a better feeling for how this works, consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1, NumberField1 }, Element.&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1; NumberField1 }; Element,&lt;span class=&quot;property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This formula returns an array consisting of the fields of the first array which
are visible. It works, because both number fields and switch fields support the
&lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt; property.&lt;/p&gt;

&lt;p&gt;Now consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1, NumberField1 }, Element.MinimumValue &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1; NumberField1 }; Element,MinimumValue &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;MinimumValue&quot;&gt;MinimumValue&lt;/span&gt; is a property of number fields. As
this property is not supported by switch fields, Calcapp Creator will show an
error message.&lt;/p&gt;

&lt;p&gt;However, if we use a logical array instead, the formula will work with no
errors:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1, NumberField1 }, { SwitchField1, NumberField1 }.MinimumValue &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1; NumberField1 }; { SwitchField1; NumberField1 },MinimumValue &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Here is the equivalent formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1, NumberField1 }, { &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(), NumberField1.&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;MinimumValue&quot;&gt;MinimumValue&lt;/span&gt; } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FILTER&quot;&gt;FILTER&lt;/span&gt;({ SwitchField1; NumberField1 }; { &lt;span class=&quot;function&quot; name=&quot;BLANK&quot;&gt;BLANK&lt;/span&gt;(); NumberField1,&lt;span class=&quot;property&quot; parent-type=&quot;NumberField&quot; name=&quot;MinimumValue&quot;&gt;MinimumValue&lt;/span&gt; } &lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula above returns an array containing both &lt;em&gt;SwitchField1&lt;/em&gt; and
&lt;em&gt;NumberField1&lt;/em&gt;, because the blank value is treated as zero by the
&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;gt;=&quot;&gt;&amp;gt;=&lt;/span&gt; operator, which passes the &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;binaryOperator&quot; name=&quot;GREATER_THAN_OR_EQUAL_TO&quot;&gt;&amp;gt;=&lt;/span&gt; 0&lt;/span&gt;
test.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 04:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/range-gotcha.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/range-gotcha.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Sample app: Convert spreadsheet tables to XLOOKUP formulas</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our latest sample app converts spreadsheet column data to formulas that use
  the XLOOKUP function. This post explains in detail how it was built.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;div class=&quot;notice&quot;&gt;
  &lt;a href=&quot;https://creator.calcapp.net/#?template=Sample%3A%20XLOOKUP%20generator
&quot; target=&quot;creator&quot;&gt;
    Create a new app based on this sample app ↗
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;August 11, 2023 update:&lt;/strong&gt; We now recommend that you use the &lt;a href=&quot;/blog/2023/08/11/data-editor.html&quot;&gt;data
editor&lt;/a&gt; to import and edit spreadsheet data. It is significantly
easier to use than the method described here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Original text:&lt;/strong&gt; We publish &lt;a href=&quot;/blog/tag/sample-app.html&quot;&gt;sample apps&lt;/a&gt; as a means of
demonstrating Calcapp features and techniques that you may want to use in your
own apps that you distribute to your own users. This sample app is different —
the intended user is you, the app author, and it helps you convert spreadsheet
data to formulas that use the new &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;Read this blog post&lt;/a&gt; to get a high-level overview of how to use this
app to import table data and to learn how XLOOKUP works. This post explains in
detail how to use the app converting spreadsheet data and how it was written.&lt;/p&gt;

&lt;p&gt;To summarize, Calcapp now supports the &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; function, which
is equivalent to the classic spreadsheet functions VLOOKUP and HLOOKUP. XLOOKUP
accepts the sought value and two arrays, one containing values to find (the
&lt;em&gt;lookup array&lt;/em&gt;) and one containing the values to return (the &lt;em&gt;result array&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;This formula returns 300, because the sought value, 30, is the third element in
the first array, which causes XLOOKUP to return the third element in the second
array, 300:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(30, { 10, 20, 30 }, { 100, 200, 300 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(30; { 10; 20; 30 }; { 100; 200; 300 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;As Calcapp does not &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;yet&lt;/a&gt; have native support for data tables, the
data must be converted to XLOOKUP formulas. That’s the job of this app.&lt;/p&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;p&gt;Here’s an embedded version of the app, which you can also
&lt;a href=&quot;https://connect.calcapp.net/?app=dtoyel&quot; target=&quot;connect&quot;&gt;run as a
stand-alone app&lt;/a&gt;:&lt;/p&gt;

&lt;iframe seamless=&quot;&quot; style=&quot;height: 665px; width: 100%; max-width: 768px; border: none;&quot; src=&quot;https://connect.calcapp.net/?app=dtoyel&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;For step-by-step instructions on how to use this app, refer to &lt;a href=&quot;/blog/2021/11/12/xlookup.html&quot;&gt;this blog
post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Copy the lookup values from a spreadsheet table and paste them into the &lt;strong&gt;Lookup
values&lt;/strong&gt; field. Then, copy the result values and paste them into the &lt;strong&gt;Result
values&lt;/strong&gt; field. The generated XLOOKUP formula then becomes available.&lt;/p&gt;

&lt;p&gt;Be sure to select the decimal separator you’re using using the &lt;strong&gt;Decimal
separator&lt;/strong&gt; field, to ensure that the generated formula works well with Calcapp
Creator. If you use a decimal comma as a decimal separator, the app will use
semicolons to separate parameters. If you use a decimal point as a decimal
separator, the app will use commas to separate parameters.&lt;/p&gt;

&lt;p&gt;Also, the app automatically detects if the values are numbers or text. If they
are numbers (potentially starting with a currency symbol, such as “$”), the
elements of the generated array are not quoted, ensuring that you get numbers —
and not text — back when you call the function.&lt;/p&gt;

&lt;h2 id=&quot;under-the-hood&quot;&gt;Under the hood&lt;/h2&gt;

&lt;p&gt;This app makes heavy use of Calcapp’s new &lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;formula engine&lt;/a&gt;,
which we introduced with our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;November release&lt;/a&gt;. Thanks
to the new features, this app is considerably simpler than the &lt;a href=&quot;/blog/2018/04/06/column-converter.html&quot;&gt;sample app that
generates CHOOSE formulas&lt;/a&gt; we wrote in 2018.&lt;/p&gt;

&lt;p&gt;You’re encouraged to view the app and its formulas as you read along. It’s
available as a template when you create a new app under the &lt;em&gt;Sample: XLOOKUP
generator&lt;/em&gt; name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This post explains in detail how the XLOOKUP generator app is
implemented. Feel free to skip it altogether if you’re just interested in using
the app and not in how it was written.&lt;/p&gt;

&lt;h2 id=&quot;handling-separators&quot;&gt;Handling separators&lt;/h2&gt;

&lt;p&gt;This app works with both decimal points and decimal commas. It is important for
the app to have access to this information, because the generated XLOOKUP
formula uses commas as a parameter separator if a decimal point is selected and
semicolons otherwise. Also, the app recognizes when users enter numbers as
lookup or result values and leaves out quotation marks if that is the case.&lt;/p&gt;

&lt;p&gt;There is a text drop-down field named &lt;em&gt;Decimal separator&lt;/em&gt;. In order to insulate
the rest of the app from having to know about the actual wording of the options
available to the user, there are two &lt;a href=&quot;/blog/2016/09/08/hidden-fields.html&quot;&gt;hidden text fields&lt;/a&gt; that
expose the chosen decimal separator and parameter separator as text strings.&lt;/p&gt;

&lt;p&gt;The first is named &lt;em&gt;DecimalSeparatorText&lt;/em&gt; and this is its value formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(DecimalSeparator &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Decimal point&quot;, &quot;.&quot;, &quot;,&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(DecimalSeparator &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Decimal point&quot;; &quot;.&quot;; &quot;,&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The second is named &lt;em&gt;ParameterSeparatorText&lt;/em&gt; and this is its value formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(DecimalSeparator &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Decimal point&quot;, &quot;,&quot;, &quot;;&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(DecimalSeparator &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; &quot;Decimal point&quot;; &quot;,&quot;; &quot;;&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;detecting-numbers-with-a-regular-expression&quot;&gt;Detecting numbers with a regular expression&lt;/h2&gt;

&lt;p&gt;It is important that the app can recognize numbers. To do so, we would normally
use a function like &lt;span class=&quot;link function&quot; name=&quot;PARSENUMBER&quot;&gt;PARSENUMBER&lt;/span&gt;, which returns an error if the
given text string is not a number and the parameter as a number otherwise. This
doesn’t work with this app, though, as it needs to be able to work with both
decimal points and decimal commas.&lt;/p&gt;

&lt;p&gt;PARSENUMBER does not work for this app, as it takes the language of the app into
account and its decimal separator (a decimal point for US English and a decimal
comma for German, for instance). PARSENUMBER can’t be coaxed into working with
decimal commas if the language of the app uses a decimal point, and vice versa.&lt;/p&gt;

&lt;p&gt;As a result, we need to detect if a text string is a number using a &lt;a href=&quot;/blog/2018/04/06/regular-expressions.html&quot;&gt;regular
expression&lt;/a&gt;. These text strings can be notoriously tricky
to get right, and we’ll be the first to admit that writing this sample app
required a trip to the excellent &lt;a href=&quot;https://regex101.com/&quot;&gt;regex101.com&lt;/a&gt; to make our regular
expression work.&lt;/p&gt;

&lt;p&gt;(Have you never heard of regular expressions before? They are a powerful tool to
work with text. We wrote &lt;a href=&quot;/blog/2018/04/06/regular-expressions.html&quot;&gt;a lengthy introduction&lt;/a&gt; back in
2018 when Calcapp gained support for them. Be sure to read that post first if
you want to understand this section. If not, feel free to skip ahead.)&lt;/p&gt;

&lt;p&gt;To determine if a text string matches a regular expression, we need to use the
&lt;span class=&quot;link function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt; function. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d&lt;/code&gt; matches a single digit, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d+&lt;/code&gt;
matches one or multiple digits.&lt;/p&gt;

&lt;p&gt;As a result, both these formulas return TRUE, indicating that both “123” and
“123456789” match the regular expression &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d+&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&quot;123&quot;, &quot;\d+&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&quot;123&quot;; &quot;\d+&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&quot;123456789&quot;, &quot;\d+&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&quot;123456789&quot;; &quot;\d+&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The regular expression &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d+&lt;/code&gt; can be used to match multiple integers, but what
about decimal numbers? If a decimal point is used, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d+\.\d+&lt;/code&gt; matches a decimal
number. (The backslash before the period is there because periods are otherwise
special characters in regular expressions that match anything. With a backslash,
the period in the formula above matches a literal period.)&lt;/p&gt;

&lt;p&gt;To make the regular expression work for arbitrary numbers — integers or decimal
numbers — we need to make the decimal part optional. Consider this regular
expression:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\d+(\.\d+)?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The part in parentheses matches the decimal part of the number. By putting a
question mark after the closing parenthesis, the entire decimal part is made
optional.&lt;/p&gt;

&lt;p&gt;There are five more changes we need to make to make the regular expression
complete, though. First, it must accept negative numbers, so we add a leading
minus sign, followed by a question mark to make the minus sign optional:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-?\d+(\.\d+)?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Second, it must accept numbers that are preceded by a currency symbol (such as
“$”). We don’t want these lines to count as text lines. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\p{Sc}&lt;/code&gt; matches a
currency symbol in a regular expression. It needs to go after the minus sign:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-?\p{Sc}?\d+(\.\d+)?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Third, we need to accept decimal numbers where the zero isn’t spelled out (like
in .1). To do so, we must change the first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; character, which accepts one or
multiple digits, to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; character, which accepts zero or multiple digits:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-?\p{Sc}?\d*(\.\d+)?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Fourth, we only want to accept text strings that only consist of numbers,
meaning that “3a” or “a3” should not qualify. To do so, we need to add so-called
&lt;em&gt;anchors&lt;/em&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^&lt;/code&gt; represents the beginning of the text string, and is added first,
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt; represents the end of the text string, and is added last:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^-?\p{Sc}?\d*(\.\d+)?$&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Above, the anchors prevent arbitrary text from appearing between the beginning
of the text string and the number, and between the number and the end of the
text string.&lt;/p&gt;

&lt;p&gt;Finally, we need to accept a decimal comma and not a decimal point if that is
the user’s preference. Remember that the symbol the user prefers is stored as
the value of the &lt;em&gt;DecimalSeparatorText&lt;/em&gt; hidden field. That means that we need to
replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\.&lt;/code&gt; in the expression with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\,&lt;/code&gt; if that is the case. (A leading
backslash isn’t strictly speaking needed here, as a comma has no special meaning
in this context. It does no harm, though, so it stays.) We use the
&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; operator to join together the various pieces of the expression
we need.&lt;/p&gt;

&lt;p&gt;Putting it all together, this is the formula for the value of the hidden field
&lt;em&gt;NumberRegex&lt;/em&gt;, which we’ll refer back to from other formulas later:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;^-?\p{Sc}?\d*(\&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; DecimalSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;\d+)?$&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;^-?\p{Sc}?\d*(\&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; DecimalSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;\d+)?$&quot;&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;determining-if-a-text-field-only-consists-of-numeric-lines-of-text&quot;&gt;Determining if a text field only consists of numeric lines of text&lt;/h2&gt;

&lt;p&gt;Users are expected to paste their lookup values into the &lt;em&gt;LookupValues&lt;/em&gt; text
field and their result values into the &lt;em&gt;ResultValues&lt;/em&gt; text field. Below each of
them, we add two hidden logical fields which determine if the text fields only
hold numbers, named &lt;em&gt;LookupValuesAreNumbers&lt;/em&gt; and &lt;em&gt;ResultValuesAreNumbers&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It is possible to use the &lt;span class=&quot;link function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt; function directly with text
strings consisting of multiple lines. However, we won’t do that here, instead
we’ll use the new &lt;span class=&quot;link function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt; function to create an array of text
strings (with one line per array element) from the original text string. If
you’re interested in the other approach, refer to our write-up for the app
producing &lt;a href=&quot;/blog/2018/04/06/column-converter.html&quot;&gt;CHOOSE formulas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;TEXTSPLIT breaks a text string apart and returns the pieces as an array of text
strings. This formula returns the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ &quot;1&quot;, &quot;2&quot;, &quot;3&quot; }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ &quot;1&quot;; &quot;2&quot;; &quot;3&quot; }&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(&quot;1-2-3&quot;, &quot;-&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(&quot;1-2-3&quot;; &quot;-&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In the formula above, “-“ is used as the delimiter between the returned array
elements. With a text field accepting multiple lines, the delimiter we are
looking for is a line break character, which the new &lt;span class=&quot;link function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;
function returns.&lt;/p&gt;

&lt;p&gt;As such, this formula breaks the text string &lt;em&gt;LookupValues&lt;/em&gt; apart, returning an
array of the lines of text it consists of:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To determine if the individual text lines can be considered numbers, we can
invoke the &lt;span class=&quot;link function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt; function directly on the array:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()), NumberRegex)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()); NumberRegex)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The second parameter is set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NumberRegex&lt;/code&gt;, which is the hidden text field we
constructed earlier holding the regular expression which matches numbers.&lt;/p&gt;

&lt;p&gt;REGEXMATCH normally accepts two parameters (and a few optional parameters we
won’t discuss here). The first one is a text string to match against a regular
expression, given as the second parameter. It returns TRUE if the regular
expression matches the given text string and FALSE otherwise.&lt;/p&gt;

&lt;p&gt;Our new formula engine ensures that REGEXMATCH can also work with arrays. If the
first parameter is an array — which it is, in this case — the result is also an
array. Specificially, the result is an array of logical values, with the same
size as the original text array. If &lt;span class=&quot;formula decimalpoint&quot;&gt;{ TRUE, FALSE, TRUE }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ TRUE; FALSE; TRUE }&lt;/span&gt; is
returned, that means that the array given to REGEXMATCH contains three elements,
and that the first and third elements match the regular expression given as the
second parameter, while the second element does not.&lt;/p&gt;

&lt;p&gt;So how do we go from a logical array, where each element signifies whether a
single line can be interpreted as a number, to a single logical value, where
TRUE means that all elements can be interpreted as numbers and FALSE indicates
that there is at least one element that does not qualify?&lt;/p&gt;

&lt;p&gt;Enter &lt;span class=&quot;link function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;. This formula returns FALSE, because there is at least
one FALSE element:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ TRUE, TRUE, FALSE, TRUE, TRUE }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ TRUE; TRUE; FALSE; TRUE; TRUE }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;AND only returns TRUE if all elements given to it are TRUE. This formula returns
TRUE:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ TRUE, TRUE, TRUE, TRUE, TRUE }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ TRUE; TRUE; TRUE; TRUE; TRUE }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Putting it all together, this is the formula associated with the value of the
&lt;em&gt;LookupValuesAreNumbers&lt;/em&gt; hidden field:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()), NumberRegex))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;REGEXMATCH&quot;&gt;REGEXMATCH&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()); NumberRegex))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The formula for the &lt;em&gt;ResultValuesAreNumbers&lt;/em&gt; hidden field is similar.&lt;/p&gt;

&lt;h2 id=&quot;generating-the-xlookup-formula&quot;&gt;Generating the XLOOKUP formula&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;GeneratedXLOOKUPFormula&lt;/em&gt; field contains the generated formula. The formula
of the value of this field uses the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; operator heavily to join
text strings together. It makes use of the hidden field &lt;em&gt;ParameterSeparatorText&lt;/em&gt;
to ensure that it inserts the proper parameter separator (a comma if a decimal
point is used and a semicolon otherwise).&lt;/p&gt;

&lt;p&gt;There are two final hidden fields we need in order to make the formula for the
value of the &lt;em&gt;GeneratedXLOOKUPFormula&lt;/em&gt; field more readable. They are named
&lt;em&gt;LookupQuoteIfNeeded&lt;/em&gt; and &lt;em&gt;ResultQuoteIfNeeded&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The idea is that these hidden fields should contain a single quotation mark (“),
but only if the corresponding text field does not exclusively contain lines that
can be interpreted as numbers. These hidden text fields can then be referenced
from the final formula as an easy means of inserting quotation marks, but only
if they are needed.&lt;/p&gt;

&lt;p&gt;Here’s the formula for the value property of the &lt;em&gt;LookupQuoteIfNeeded&lt;/em&gt; field:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;LookupValuesAreNumbers, &quot;&quot;&quot;&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;LookupValuesAreNumbers; &quot;&quot;&quot;&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The second parameter to IF may look a bit odd, but that’s actually how a single
quotation mark is written in Calcapp (and in spreadsheets). Of the four
quotation marks, the first and the last demarcate the text string. To write a
single quotation mark, two quotation marks must be written, because a single one
would end the text string prematurely.&lt;/p&gt;

&lt;p&gt;Before we look at the final formula, let’s look at the expected results from the
app. Let’s say that we have a very simple table, consisting of only two rows and
two columns. Here it is:&lt;/p&gt;

&lt;table class=&quot;data-table&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;Name&lt;/th&gt;
    &lt;th&gt;Age&lt;/th&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Louise&lt;/td&gt;
    &lt;td&gt;53&lt;/td&gt;
  &lt;/tr&gt;

  &lt;tr&gt;
    &lt;td&gt;Ahmed&lt;/td&gt;
    &lt;td&gt;28&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;The user is expected to paste the contents of the first column into the
&lt;em&gt;LookupValues&lt;/em&gt; field, and the contents of the second column into the
&lt;em&gt;ResultValues&lt;/em&gt; field. We then want the app to generate this formula if the
preferred decimal separator is a decimal point:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;XLOOKUP(SoughtValue, { &quot;Louise&quot;, &quot;Ahmed&quot; }, { 53, 28 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;XLOOKUP(SoughtValue, { &quot;Louise&quot;, &quot;Ahmed&quot; }, { 53, 28 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We want the app to generate this formula if the preferred decimal separator is a
decimal comma:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;XLOOKUP(SoughtValue; { &quot;Louise&quot;; &quot;Ahmed&quot; }, { 53; 28 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;XLOOKUP(SoughtValue; { &quot;Louise&quot;; &quot;Ahmed&quot; }, { 53; 28 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Before we move on to the final formula that generates the formulas above, let’s
consider what it takes to generate just the arrays to XLOOKUP. We have already
concluded that we can convert the value of the &lt;em&gt;LookupValues&lt;/em&gt; text field
(complete with &lt;span class=&quot;link function&quot; name=&quot;NEWLINE&quot;&gt;line breaks&lt;/span&gt;) to an array of its
constituent lines with this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;How do we put it back together to form a text string, once more, this time with
different delimiters? Remember that the delimiter used above is a line break.
This time around, we want the delimiter to be a parameter separator character (a
comma or a semicolon), followed by a space for readability.&lt;/p&gt;

&lt;p&gt;To achieve this, we use the &lt;span class=&quot;link function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt; function. This formula does
exactly what is described in the preceding paragraph:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot;, TRUE, &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot;; TRUE; &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(The second parameter, TRUE, instructs TEXTJOIN to ignore &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank values&lt;/span&gt;.)&lt;/p&gt;

&lt;p&gt;Now, what if the lookup values consist of text strings (meaning that the value
of the &lt;em&gt;LookupValuesAreNumbers&lt;/em&gt; hidden field is FALSE)? Then we need to use not
only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;,&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; as delimiters, but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot; , &quot;&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot; ; &quot;&lt;/code&gt; (so that the elements of
the array end with and start with a quotation mark).&lt;/p&gt;

&lt;p&gt;This formula does just that:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded, TRUE, &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded; TRUE; &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To truly generate an array, though, we also need the begin and end braces, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;}&lt;/code&gt;. Also, we potentially need to add quotation marks to the beginning of
the first element and to the end of the last element.&lt;/p&gt;

&lt;p&gt;Here’s the formula for a hidden text field named &lt;em&gt;GeneratedLookupArray&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;{ &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded , TRUE, &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; }&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;{ &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded ; TRUE; &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(LookupValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; LookupQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; }&quot;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;There is a similar hidden text field named &lt;em&gt;GeneratedResultArray&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the complete formula, combining the values of &lt;em&gt;GeneratedLookupArray&lt;/em&gt; and
&lt;em&gt;GeneratedResultArray&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;XLOOKUP(&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; SoughtValue &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; GeneratedLookupArray &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; GeneratedResultArray &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;)&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;XLOOKUP(&quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; SoughtValue &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; GeneratedLookupArray &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;, &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; GeneratedResultArray &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot;)&quot;&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;one-last-thing&quot;&gt;One last thing&lt;/h2&gt;

&lt;p&gt;At first blush, the complete formula above appears to work very well. It works
for plain numbers and it works for text strings.&lt;/p&gt;

&lt;p&gt;However, what about numbers that are preceded by currency symbols? The
&lt;em&gt;NumberRegex&lt;/em&gt; field treats them as numbers, which leads this app to generate an
XLOOKUP formula such as this one:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(SoughtValue, { &quot;Louise&quot;, &quot;Ahmed&quot; }, { $53, $28 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt;(SoughtValue; { &quot;Louise&quot;; &quot;Ahmed&quot; }; { $53; $28 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;That’s not a valid Calcapp formula — numbers can’t be preceded by currency
symbols.&lt;/p&gt;

&lt;p&gt;To fix this problem, we need to take steps to remove the currency symbols. To do
so, we’ll modify the TEXTSPLIT parts of the formulas for the values of
&lt;em&gt;GeneratedLookupArray&lt;/em&gt; and &lt;em&gt;GeneratedResultArray&lt;/em&gt;. Here is part of the formula
for the value of &lt;em&gt;GeneratedResultArray&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;())&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(We’ll show this exclusively for result values, the formula for the value of
&lt;em&gt;GeneratedLookupArray&lt;/em&gt; also needs to be modified.)&lt;/p&gt;

&lt;p&gt;First off, if the result values are not numbers, the formula above is exactly
what we need — no currency symbols should be removed. We’ll achieve this with
&lt;span class=&quot;link function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ResultValuesAreNumbers, …, &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ResultValuesAreNumbers; …, &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We’ll need to replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;…&lt;/code&gt; in the formula above with a
formula fragment that removes currency symbols.&lt;/p&gt;

&lt;p&gt;To achieve this, we’ll rely on another regular expression:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;([\P{Sc}]*)\p{Sc}?(.*)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\P{Sc}&lt;/code&gt; means “not a currency symbol” and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\p{Sc}&lt;/code&gt; means “a currency symbol.”
What this regular expression does is that it divides a text string into two
halves (captured by two &lt;em&gt;capturing groups&lt;/em&gt;), one consisting of the text that
appears before a currency symbol and one consisting of the text that appears
after. The currency symbol itself appears between the two halves and is not part
of either capturing group.&lt;/p&gt;

&lt;p&gt;(Capturing groups appear between parentheses in regular expressions and capture
text, in this case the two halves mentioned above.)&lt;/p&gt;

&lt;p&gt;The &lt;span class=&quot;link function&quot; name=&quot;REGEXEXTRACT&quot;&gt;REGEXEXTRACT&lt;/span&gt; function can be used to extract the text
captured by a capturing group. To use it, we need to provide the number of the
capturing group as the third parameter (1 or 2, in this case, as there are two
capturing groups).&lt;/p&gt;

&lt;p&gt;Using REGEXEXTRACT would work — but would not be ideal, as we’d then need to
repeat the REGEXEXTRACT invocation (once with 1 as the third parameter and once
with 2 as the second parameter) and merge together the results using the
&lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; operator.&lt;/p&gt;

&lt;p&gt;The new &lt;span class=&quot;link function&quot; name=&quot;REGEXEXTRACTALL&quot;&gt;REGEXEXTRACTALL&lt;/span&gt; function is different from REGEXEXTRACT
in that it returns the contents of all capturing groups as an array. That’s
perfect, as we can then merge together the two halves (without the currency
symbol) not with &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt;, but with &lt;span class=&quot;link function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;, with a
delimiter set to &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;&quot;&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the formula with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;…&lt;/code&gt; part filled in:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ResultValuesAreNumbers, &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;&quot;, FALSE, &lt;span class=&quot;function&quot; name=&quot;REGEXEXTRACTALL&quot;&gt;REGEXEXTRACTALL&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()), &quot;([\P{Sc}]&lt;em&gt;)\p{Sc}?(.&lt;/em&gt;)&quot;)), &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ResultValuesAreNumbers; &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;&quot;; FALSE; &lt;span class=&quot;function&quot; name=&quot;REGEXEXTRACTALL&quot;&gt;REGEXEXTRACTALL&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()); &quot;([\P{Sc}]&lt;em&gt;)\p{Sc}?(.&lt;/em&gt;)&quot;)); &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Here’s the complete formula for &lt;em&gt;GeneratedResultArray&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;{ &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ResultQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(ResultQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ResultQuoteIfNeeded, TRUE, &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ResultValuesAreNumbers, &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;&quot;, FALSE, &lt;span class=&quot;function&quot; name=&quot;REGEXEXTRACTALL&quot;&gt;REGEXEXTRACTALL&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()), &quot;([\P{Sc}]&lt;em&gt;)\p{Sc}?(.&lt;/em&gt;)&quot;)), &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues, &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ResultQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; }&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;{ &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ResultQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(ResultQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ParameterSeparatorText &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ResultQuoteIfNeeded; TRUE; &lt;span class=&quot;function&quot; name=&quot;IF&quot;&gt;IF&lt;/span&gt;(ResultValuesAreNumbers; &lt;span class=&quot;function&quot; name=&quot;TEXTJOIN&quot;&gt;TEXTJOIN&lt;/span&gt;(&quot;&quot;; FALSE; &lt;span class=&quot;function&quot; name=&quot;REGEXEXTRACTALL&quot;&gt;REGEXEXTRACTALL&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()); &quot;([\P{Sc}]&lt;em&gt;)\p{Sc}?(.&lt;/em&gt;)&quot;)); &lt;span class=&quot;function&quot; name=&quot;TEXTSPLIT&quot;&gt;TEXTSPLIT&lt;/span&gt;(ResultValues; &lt;span class=&quot;function&quot; name=&quot;NEWLINE&quot;&gt;NEWLINE&lt;/span&gt;()))) &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; ResultQuoteIfNeeded &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; &quot; }&quot;&lt;/span&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 03:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/xlookup-generator.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/xlookup-generator.html</guid>
        
        <category>Sample app</category>
        
        
      </item>
    
      <item>
        <title>Backward compatibility and our new formula engine</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We work hard to ensure that your apps continue working, even as we add
  features to Calcapp. With our new formula engine, we have made some minor
  changes, but they should not affect your existing apps.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;We take backwards compatibility seriously. What that means is that we work hard
to ensure that your apps continue working, even as we add features to Calcapp.&lt;/p&gt;

&lt;p&gt;We realize that the apps you build with Calcapp are often used in
business-critical situations, and the last thing you need is to have — say — a
production line grind to a halt just because we made some changes. We also
realize that many apps are built by staff members who may no longer be with an
organization a year or two down the road, and that making changes to existing
apps can be difficult for many organizations. In other words, apps should never
break.&lt;/p&gt;

&lt;p&gt;This &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;release&lt;/a&gt; does bring with it a completely revamped
&lt;a href=&quot;/blog/2021/11/12/formula-engine.html&quot;&gt;formula engine&lt;/a&gt;, though, and there are some rare edge cases
where formulas now behave differently.&lt;/p&gt;

&lt;p&gt;We don’t think that this will affect your apps, though. We have manually tested
most public apps on a paid plan with both the old Calcapp version and the
current version, and the apps behave identically. We have also used automated
tools to scan your formulas for potential problems and have turned up
empty-handed.&lt;/p&gt;

&lt;p&gt;Had Calcapp been a conventional desktop application, things would have been
different. We wouldn’t have had access to your apps and your formulas, and
making any backward-incompatible changes — however minor — would have been
unthinkable. We’re glad that we do have access to the apps run on our platform,
because that gives us the opportunity to make small changes to the way apps
work.&lt;/p&gt;

&lt;p&gt;In other words, we don’t think that this new release should cause your apps to
perform differently. If that isn’t the case, though, and you do experience
issues, please &lt;a href=&quot;mailto:support@calcapp.net&quot;&gt;contact us&lt;/a&gt; immediately. We’ll work with you to
resolve any issues — at no additional cost to you.&lt;/p&gt;

&lt;h2 id=&quot;backward-incompatible-changes&quot;&gt;Backward-incompatible changes&lt;/h2&gt;

&lt;p&gt;This is a list of changes that result in formulas behaving differently in edge
cases. If you’re not particularly interested in formulas, and your apps seem to
work just fine, this is probably dry reading.&lt;/p&gt;

&lt;h3 id=&quot;colors&quot;&gt;Colors&lt;/h3&gt;

&lt;p&gt;We pride ourselves on being able to detect lots of formula errors at an early
stage. What that means is that you get clear error messages directly in Calcapp
Creator, instead of getting puzzling behavior when you run your app.&lt;/p&gt;

&lt;p&gt;If you, for instance, try to associate the formula &lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;test&quot;&lt;/span&gt;
with the &lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;value of a number field&lt;/span&gt;, Calcapp
Creator would let you know that it expected a number, but unexpectedly found a
text string. (It will then offer to convert your number field to a text field.)&lt;/p&gt;

&lt;p&gt;Prior to this release, Calcapp supported only numbers, text strings and logical
values. You had to express a date or a time as a number, and that was also true
for colors.&lt;/p&gt;

&lt;p&gt;The problem with using numbers for things that aren’t strictly speaking numbers
is that you lose Calcapp’s ability to flag formula errors early. If you set the
&lt;span class=&quot;link property&quot; parent-type=&quot;DateTimeField&quot; name=&quot;Value&quot;&gt;value of a date and time field&lt;/span&gt; to 42,
Calcapp won’t complain, as that’s a valid &lt;a href=&quot;/blog/2016/05/28/dates.html&quot;&gt;sequential serial number&lt;/a&gt;.
Likewise, if you set the &lt;span class=&quot;link property&quot; parent-type=&quot;Screen&quot; name=&quot;BackgroundColor&quot;&gt;background color of a screen&lt;/span&gt; to &lt;span class=&quot;formula decimalpoint&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100&lt;/span&gt;, an older version of Calcapp
would have accepted the formula.&lt;/p&gt;

&lt;p&gt;We have seen lots of formulas likely intended for the
&lt;span class=&quot;link property&quot; parent-type=&quot;NumberField&quot; name=&quot;Value&quot;&gt;value properties of number fields&lt;/span&gt;
erroneously associated with color properties instead. That leads to colors
being off and to formulas carefully written by app authors seemingly not having
an effect.&lt;/p&gt;

&lt;p&gt;To solve this problem, colors are no longer numbers in Calcapp, they are colors
(a separate &lt;em&gt;type&lt;/em&gt;). Functions like &lt;span class=&quot;link function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt; now return colors and
not numbers, and functions like &lt;span class=&quot;link function&quot; name=&quot;HUE&quot;&gt;HUE&lt;/span&gt; accept color parameters, not
number parameters. Any attempt to associate a formula like
&lt;span class=&quot;formula decimalpoint&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Field1 &lt;span class=&quot;binaryOperator&quot; name=&quot;MULTIPLICATION&quot;&gt;*&lt;/span&gt; 100&lt;/span&gt; with a color property will now be flagged as an
error.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/learn/colors.html#advanced-how-calcapp-represents-colors&quot;&gt;If you know what you’re doing&lt;/a&gt;, treating a color as a number can be
useful. For that reason, there is a new function, &lt;span class=&quot;link function&quot; name=&quot;TOCOLOR&quot;&gt;TOCOLOR&lt;/span&gt;, which
allows you to convert a number to a color. Use &lt;span class=&quot;link function&quot; name=&quot;TONUMBER&quot;&gt;TONUMBER&lt;/span&gt; to
convert a color to a number.&lt;/p&gt;

&lt;p&gt;Truth be told, we undertook this ambitious change with a view towards making
dates and times distinct from numbers too. That would have made it illegal to do
something like taking the square root of a date and time value, which is never
useful.&lt;/p&gt;

&lt;p&gt;However, we came to realize that advanced spreadsheet users (some of whom are
our valued customers) are very much familiar with how date and time values work.
(The integer part of the number represents the number of days that have elapsed
since December 31, 1899.) Some advanced users put numeric values representing
various dates in formulas directly, without using functions like
&lt;span class=&quot;link function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;TIME&quot;&gt;TIME&lt;/span&gt;. As a result, we abandoned that
part of the plan — date and time values will remain numbers.&lt;/p&gt;

&lt;p&gt;So what happens if your perfectly-functional app uses colors in a way that
Calcapp now considers invalid? They have &lt;a href=&quot;/blog/2021/11/12/large-apps.html#making-information-about-your-app-easily-accessible&quot;&gt;automatically&lt;/a&gt; been
rewritten to use the &lt;span class=&quot;link function&quot; name=&quot;TOCOLOR&quot;&gt;TOCOLOR&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;TONUMBER&quot;&gt;TONUMBER&lt;/span&gt;
functions, meaning that your apps will continue working exactly as they did
before.&lt;/p&gt;

&lt;h3 id=&quot;renamed-properties&quot;&gt;Renamed properties&lt;/h3&gt;

&lt;p&gt;This release &lt;a href=&quot;/blog/2021/11/12/new-names.html&quot;&gt;brings with it various name changes&lt;/a&gt;. Notably, panels
are now named &lt;em&gt;screens&lt;/em&gt; and list panel options are now named &lt;em&gt;navigators&lt;/em&gt;. Those
name changes affect the naming of two properties.&lt;/p&gt;

&lt;p&gt;Specifically, the &lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;form screen&lt;/span&gt; and
&lt;span class=&quot;link property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;text screen&lt;/span&gt; property
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NextScreenAvailable&lt;/code&gt; used to be named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NextPanelAvailable&lt;/code&gt;. Also, the
&lt;span class=&quot;link property&quot; parent-type=&quot;Screen&quot; name=&quot;NavigatorLabelColor&quot;&gt;NavigatorLabelColor&lt;/span&gt; property of screens used to be named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OptionLabelColor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These properties are rarely referenced from formulas. However, it does happen.
This formula could be associated with the &lt;span class=&quot;link property&quot; parent-type=&quot;TextBox&quot; name=&quot;Visible&quot;&gt;Visible&lt;/span&gt;
property of a text box to only show it if the next screen is not available:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;FormScreen1.&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;unaryOperator&quot; name=&quot;NEGATION&quot;&gt;!&lt;/span&gt;FormScreen1,&lt;span class=&quot;property&quot; parent-type=&quot;FormScreen&quot; name=&quot;NextScreenAvailable&quot;&gt;NextScreenAvailable&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;(Perhaps the text box has information on how to fill out the form so that the
user is allowed to progress to the next screen.)&lt;/p&gt;

&lt;p&gt;If you referenced any of these two properties from your formulas, these formulas
have &lt;a href=&quot;/blog/2021/11/12/large-apps.html#making-information-about-your-app-easily-accessible&quot;&gt;automatically&lt;/a&gt; been rewritten to use the new names.&lt;/p&gt;

&lt;h3 id=&quot;the--and--operators&quot;&gt;The == and != operators&lt;/h3&gt;

&lt;p&gt;Prior to &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;this release&lt;/a&gt;, the &lt;span class=&quot;link binaryOperator&quot; name=&quot;=&quot;&gt;=&lt;/span&gt; and
&lt;span class=&quot;link binaryOperator&quot; name=&quot;==&quot;&gt;==&lt;/span&gt; operators were identical, as were the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;lt;&amp;gt;&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; and
&lt;span class=&quot;link binaryOperator&quot; name=&quot;!=&quot;&gt;!=&lt;/span&gt; operators.&lt;/p&gt;

&lt;p&gt;Our new release makes them behave slightly differently, especially in regards to
arrays. These two formulas are not equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; { 1, 3, 2 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; { 1; 3; 2 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;{ 1, 2, 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;SIMPLE_EQUALITY&quot;&gt;==&lt;/span&gt; { 1, 3, 2 }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ 1; 2; 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;SIMPLE_EQUALITY&quot;&gt;==&lt;/span&gt; { 1; 3; 2 }&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first formula returns the array &lt;span class=&quot;formula decimalpoint&quot;&gt;{ TRUE, FALSE, FALSE }&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;{ TRUE; FALSE; FALSE }&lt;/span&gt;,
indicating that the elements appearing in the first position of both arrays are
identical, but that the others are not. To determine if all elements match, you
need to wrap the result array with the &lt;span class=&quot;link function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt; function:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;({ 1, 2, 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; { 1, 3, 2 })&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;AND&quot;&gt;AND&lt;/span&gt;({ 1; 2; 3 } &lt;span class=&quot;binaryOperator&quot; name=&quot;EQUALITY&quot;&gt;=&lt;/span&gt; { 1; 3; 2 })&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;An easier way to achieve this is to use &lt;span class=&quot;link binaryOperator&quot; name=&quot;==&quot;&gt;==&lt;/span&gt;. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;==&lt;/code&gt; formula
above returns FALSE, indicating that the two arrays are not identical. The
&lt;span class=&quot;link binaryOperator&quot; name=&quot;==&quot;&gt;==&lt;/span&gt; operator does an element-for-element comparison of the two
arrays and returns TRUE only if all elements match.&lt;/p&gt;

&lt;p&gt;From a backward compatibility perspective, this is not relevant, as prior
Calcapp releases did not support arrays. However, &lt;span class=&quot;link binaryOperator&quot; name=&quot;=&quot;&gt;=&lt;/span&gt; and
&lt;span class=&quot;link binaryOperator&quot; name=&quot;==&quot;&gt;==&lt;/span&gt; differ in one respect that is relevant for existing apps.&lt;/p&gt;

&lt;p&gt;Specifically, when these operators are used to compare text strings,
&lt;span class=&quot;link binaryOperator&quot; name=&quot;=&quot;&gt;=&lt;/span&gt; is case-insensitive, meaning that “A” and “a” are considered
equal. This is the traditional spreadsheet behavior, necessitating the use of
the &lt;span class=&quot;link function&quot; name=&quot;EXACT&quot;&gt;EXACT&lt;/span&gt; function to determine if two text strings are truly
identical.&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;link binaryOperator&quot; name=&quot;==&quot;&gt;==&lt;/span&gt; is now case-sensitive, meaning that “A” and “a” are not
considered equal. This would break backward compatibility, which is why we
change all formulas so that they use &lt;span class=&quot;link binaryOperator&quot; name=&quot;=&quot;&gt;=&lt;/span&gt; instead of
&lt;span class=&quot;link binaryOperator&quot; name=&quot;==&quot;&gt;==&lt;/span&gt;, and &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;lt;&amp;gt;&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt; instead of &lt;span class=&quot;link binaryOperator&quot; name=&quot;!=&quot;&gt;!=&lt;/span&gt;.&lt;/p&gt;

&lt;h3 id=&quot;some-properties-no-longer-return-blank-values&quot;&gt;Some properties no longer return blank values&lt;/h3&gt;

&lt;p&gt;Color properties have, &lt;a href=&quot;/blog/2017/08/31/validation-colors.html&quot;&gt;since their inception&lt;/a&gt;, never
returned blank values. If you access the &lt;span class=&quot;link property&quot; parent-type=&quot;Screen&quot; name=&quot;BackgroundColor&quot;&gt;background color&lt;/span&gt; of a screen, it returns the background color it uses, even if
there is no formula associated with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;BackgroundColor&lt;/code&gt; property of that
screen, or if this formula returns a &lt;span class=&quot;link function&quot; name=&quot;BLANK&quot;&gt;blank value&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Visible&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enabled&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Valid&lt;/code&gt; properties now behave in the same way. That
means that if a formula references the &lt;span class=&quot;link property&quot; parent-type=&quot;Field&quot; name=&quot;Enabled&quot;&gt;Enabled&lt;/span&gt; property of
a field, the value of this property always reflects whether the field is
enabled, even if no formula is associated with that property or if that formula
returns a blank value.&lt;/p&gt;

&lt;p&gt;This change could theoretically break apps, but we have reason to believe that
no app on a paid plan is affected.&lt;/p&gt;

&lt;h3 id=&quot;decimal-separators-and-the--operator&quot;&gt;Decimal separators and the &amp;amp; operator&lt;/h3&gt;

&lt;p&gt;When the &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; operator, which joins text strings together, is used
to join a text string together with a number, the decimal separator preference
of the language the app has been configured to use is now taken into account.&lt;/p&gt;

&lt;p&gt;Consider this formula:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&quot;The answer is: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; NumberField1&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&quot;The answer is: &quot; &lt;span class=&quot;binaryOperator&quot; name=&quot;TEXT_CONCATENATION&quot;&gt;&amp;amp;&lt;/span&gt; NumberField1&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Let’s say that the value of &lt;em&gt;NumberField1&lt;/em&gt; is 1.1. If the language of the app is
set to US English, the result is “The answer is: 1.1”. If the language of the
app is set to French, the result is “The answer is: 1,1”.&lt;/p&gt;

&lt;p&gt;Previously, Calcapp would always use a decimal point in this context. With this
change — and the ability to &lt;a href=&quot;/blog/2021/11/12/decimal-separator.html&quot;&gt;use decimal commas in formulas&lt;/a&gt;
— decimal commas are now used everywhere if that is your preference (provided
that your apps use a language that uses a decimal comma).&lt;/p&gt;

&lt;p&gt;This change also applies to functions like &lt;span class=&quot;link function&quot; name=&quot;CONCATENATE&quot;&gt;CONCATENATE&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;CONCAT&quot;&gt;CONCAT&lt;/span&gt;. With these functions and &lt;span class=&quot;link binaryOperator&quot; name=&quot;&amp;amp;&quot;&gt;&amp;amp;&lt;/span&gt; now
converting numbers to text and respecting the decimal separator preference of
the app, you may no longed need to use the &lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt;
function, if you don’t need the specialized features offered by that function
(like support for thousands separators).&lt;/p&gt;

&lt;p&gt;Technically, this change could break your apps, if you explicitly access a
textual version of a number and expect to find a decimal point, even if the
language of the app uses a decimal comma. We have reason to believe that none of
our paid apps do this, though, so this change should be safe.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 02:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/backward-compatibility.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/backward-compatibility.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Feature: No more typos when referencing colors</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Colors can now be referenced with no risk of typos, thanks to &quot;enums.&quot;
  XLOOKUP, XMATCH and FORMATDATE also support enums, which help warn you of
  errors early.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Calcapp gained the ability to customize the colors of apps
&lt;a href=&quot;/blog/2017/08/31/color-formulas.html&quot;&gt;back in 2017&lt;/a&gt;. At that time, we also introduced
the &lt;span class=&quot;link function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt; function, which converts a text string to
a color.&lt;/p&gt;

&lt;h2 id=&quot;using-the-color-function&quot;&gt;Using the COLOR function&lt;/h2&gt;

&lt;p&gt;There are multiple ways to reference the color red using the COLOR function.
These formulas are all equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;red&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;red&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;rgb(255, 0, 0)&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;rgb(255, 0, 0)&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;hsl(0, 100%, 50%)&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;hsl(0, 100%, 50%)&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#f00&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#f00&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#ff0000&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;#ff0000&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The first formula refers to the color by its name and the others use text
strings which make sense to a web developer (&lt;span class=&quot;link function&quot; name=&quot;COLOR&quot;&gt;details&lt;/span&gt;).&lt;/p&gt;

&lt;p&gt;If you make a typo when typing the COLOR parameter, you will get an error when
you run your app (or get unexpected behavior, like the wrong color showing up).
That’s not ideal — getting an error in Calcapp Creator when you type your
formula makes for a much tighter feedback loop, allowing you to correct your
formula and move on to the next order of business much faster.&lt;/p&gt;

&lt;p&gt;(In fact, we have taken steps to ensure that color formulas entered in the wrong
places now &lt;a href=&quot;/blog/2021/11/12/backward-compatibility.html#colors&quot;&gt;generate errors in Calcapp Creator&lt;/a&gt; instead of just
leading to apps with puzzling behavior.)&lt;/p&gt;

&lt;h2 id=&quot;introducing-a-new-way-of-referencing-colors&quot;&gt;Introducing a new way of referencing colors&lt;/h2&gt;

&lt;p&gt;To eliminate these errors, we are introducing a new way of referencing colors:
Simply type &lt;span class=&quot;formula decimalpoint&quot;&gt;Color.&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Color,&lt;/span&gt;, followed by the name of the
color.&lt;/p&gt;

&lt;p&gt;These two formulas are equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;red&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;red&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Color.Red&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Color,Red&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;These two formulas are also equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;rebeccapurple&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;rebeccapurple&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Color.RebeccaPurple&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Color,RebeccaPurple&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Our color system supports the &lt;a href=&quot;https://material.io/design/color/the-color-system.html&quot;&gt;color palettes&lt;/a&gt; that are
part of Google’s Material Design system, which are designed to work well
together. You can reference the Material Design colors not just through the
&lt;span class=&quot;link function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt; function, but also by writing &lt;span class=&quot;formula decimalpoint&quot;&gt;Color.&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Color,&lt;/span&gt;, followed by the color name.&lt;/p&gt;

&lt;p&gt;These formulas reference the same red color from a Material Design color
palette:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;Red 500&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;Red 500&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Color.Red500&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Color,Red500&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;These formulas are also equivalent:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;Blue A700&quot;)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;COLOR&quot;&gt;COLOR&lt;/span&gt;(&quot;Blue A700&quot;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;Color.BlueA700&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;Color,BlueA700&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;more-enums&quot;&gt;More enums&lt;/h2&gt;

&lt;p&gt;In traditional programming, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Color&lt;/code&gt; is known as an &lt;em&gt;enumerated type&lt;/em&gt;, or an
&lt;em&gt;enum&lt;/em&gt; for short. Unlike a text string, which can be anything, there is a finite
number of valid enum values. For that reason, you get an early warning if an
invalid value is used.&lt;/p&gt;

&lt;p&gt;Now that enums are fully supported by our new formula engine, we have taken this
opportunity to introduce an additional five enums — with more to come.&lt;/p&gt;

&lt;p&gt;We now support the important functions &lt;span class=&quot;link function&quot; name=&quot;XLOOKUP&quot;&gt;XLOOKUP&lt;/span&gt; and
&lt;span class=&quot;link function&quot; name=&quot;XMATCH&quot;&gt;XMATCH&lt;/span&gt;, pioneered by Microsoft with &lt;a href=&quot;https://support.microsoft.com/en-us/office/what-s-new-in-excel-2021-for-windows-f953fe71-8f85-4423-bef9-8a195c7a1100&quot;&gt;Excel
2021&lt;/a&gt;. These functions support a &lt;em&gt;match mode&lt;/em&gt; and a
&lt;em&gt;search mode&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The search mode governs the order in which arrays are searched for a value. In
Excel, you need to type 1 to search starting with the first element and -1 to
search starting with the last element.&lt;/p&gt;

&lt;p&gt;This is mainly problematic in Excel because 1 and -1 aren’t very descriptive. It
can be easy to lose track of what these numbers mean.&lt;/p&gt;

&lt;p&gt;There is an added problem in Calcapp. If you forget what the search mode
parameter does in Excel, and put in something like &lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SQRT&quot;&gt;SQRT&lt;/span&gt;(16)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;SQRT&quot;&gt;SQRT&lt;/span&gt;(16)&lt;/span&gt;,
Excel will warn you right away, because it evaluates formulas immediately.
Calcapp only evaluates formulas when you run your app, meaning that errors are
presented much later.&lt;/p&gt;

&lt;p&gt;For this reason, we give you a choice. You can either use 1 and -1, which is
great if you copy and paste formulas from a spreadsheet or have become very
comfortable with these numbers, or you can use enums. 1 can also be written as
&lt;span class=&quot;formula decimalpoint&quot;&gt;SearchMode.FirstToLast&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;SearchMode,FirstToLast&lt;/span&gt; and -1 can also be written as
&lt;span class=&quot;formula decimalpoint&quot;&gt;SearchMode.LastToFirst&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;SearchMode,LastToFirst&lt;/span&gt;. These names are more descriptive, and
you’ll get an error straight away if you misspell them.&lt;/p&gt;

&lt;p&gt;We also have enums for the match mode accepted by these two functions and
for the sort order accepted by the functions &lt;span class=&quot;link function&quot; name=&quot;SORT&quot;&gt;SORT&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;RANK.AVG&quot;&gt;RANK.AVG&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;RANK.EQ&quot;&gt;RANK.EQ&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;When we &lt;a href=&quot;/blog/2018/03/06/locale-functions.html&quot;&gt;introduced&lt;/a&gt; functions like
&lt;span class=&quot;link function&quot; name=&quot;FORMATNUMBER&quot;&gt;FORMATNUMBER&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;PARSENUMBER&quot;&gt;PARSENUMBER&lt;/span&gt; in 2018, we held
off on introducing functions which could turn dates and times into text strings
and back again. The primary reason was that we felt that we wanted support for
enums to enable app authors to specify the format.&lt;/p&gt;

&lt;p&gt;Now that we have enum support, we have taken the opportunity to introduce the
functions &lt;span class=&quot;link function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;, &lt;span class=&quot;link function&quot; name=&quot;FORMATTIME&quot;&gt;FORMATTIME&lt;/span&gt;,
&lt;span class=&quot;link function&quot; name=&quot;PARSEDATE&quot;&gt;PARSEDATE&lt;/span&gt; and &lt;span class=&quot;link function&quot; name=&quot;PARSETIME&quot;&gt;PARSETIME&lt;/span&gt;. Here’s how to format a
date using a &lt;em&gt;numeric&lt;/em&gt; date format, with an enum given as the last parameter:&lt;/p&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981, 11, 14), DateFormat.Numeric)&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;&lt;span class=&quot;function&quot; name=&quot;FORMATDATE&quot;&gt;FORMATDATE&lt;/span&gt;(&lt;span class=&quot;function&quot; name=&quot;DATE&quot;&gt;DATE&lt;/span&gt;(1981; 11; 14); DateFormat,Numeric)&lt;/span&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 01:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/enums.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/enums.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Panels are now known as screens — and other name changes</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Panels have been renamed to screens to better reflect the expectations of app
  authors. There are other name changes, which better reflect how Calcapp is
  used today and how we expect it to be used tomorrow.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2021/11/12/release.html&quot;&gt;latest release&lt;/a&gt; changes some of the names that we
use:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Panels are now known as &lt;strong&gt;screens&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Calculation panels are now known as &lt;strong&gt;form screens&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;List panels are now known as &lt;strong&gt;list screens&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Text panels are now known as &lt;strong&gt;text screens&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;Calculation panel groups are now known as &lt;strong&gt;form groups&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;List screen options are now known as &lt;strong&gt;navigators&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;why-were-screens-named-panels&quot;&gt;Why were screens named panels?&lt;/h2&gt;

&lt;p&gt;Screens used to be called panels for historical reasons. We originally
envisioned them — back in 2008 — as horizontal or vertical boxes that could be
nestled inside one another, enabling flexible layouts to be built. When the
Calcapp you know today was born in 2014, these panels were used to represent
screens built in Calcapp Creator.&lt;/p&gt;

&lt;p&gt;We resisted renaming panels to screens for some time, though, because a part of
our original plan was to automatically put list panels to the left of
calculation panels on devices with big screens, like tablets and desktop
computers. (Much like the &lt;a href=&quot;https://www.google.com/search?q=settings+app+ipados&amp;amp;tbm=isch&quot;&gt;Settings app on iPadOS&lt;/a&gt;, in
fact.)&lt;/p&gt;

&lt;p&gt;However, that feature has been put on the back burner for so long now that we
don’t know when it will happen. App authors we talk to are excited about many
upcoming features, but apps that adapt better to big screens do not seem to be
high on anyone’s list of priorities.&lt;/p&gt;

&lt;p&gt;For that reason, we are now renaming panels to the one name that everyone
expects them to use — &lt;em&gt;screens&lt;/em&gt;. When we do enable apps to work better on
large-screen devices, we doubt that anyone will be upset if there is an option
that lets multiple “screens” be placed alongside one another on big-screen
devices.&lt;/p&gt;

&lt;h2 id=&quot;the-other-name-changes-are-about-the-future&quot;&gt;The other name changes are about the future&lt;/h2&gt;

&lt;p&gt;As for the other naming changes, we have picked names that better reflect how
app authors are using these constructs today, and how we think you will use them
in the future. Many calculation panels perform little in the way of
calculations, they merely collect data. Calculations may happen on another
screen, or they may not happen at all — perhaps all that collected data is
simply sent to a Slack channel through Zapier or sent in a report.&lt;/p&gt;

&lt;p&gt;With future versions of Calcapp, which will become better at storing, updating
and visualizing data, we expect this trend to continue. Calculations will be the
focus of some apps, while others will mostly collect data.&lt;/p&gt;

&lt;p&gt;Whether or not these screens are used for calculations, they definitely house
forms. Therefore, they are now &lt;em&gt;form screens&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We intend to abolish the distinction between form screens, list screens and text
screens in the future. That will enable you to collect data from “list screens”
and to enable users to navigate forward to multiple screens from “form screens.”&lt;/p&gt;

&lt;p&gt;In a future where you can add whatever you like to a screen, we need a better
name for the options that are now only part of list screens (transporting the
user to new screens). They are now known as &lt;em&gt;navigators&lt;/em&gt;. Finally, following
similar reasoning, the form screen groups that house fields are now known as
&lt;em&gt;form groups&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We expect a Calcapp with unified screens to ship as part of our &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;Calcapp 4
project&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Fri, 12 Nov 2021 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/11/12/new-names.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/11/12/new-names.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Are we there yet?</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  We&apos;re hard at work polishing our new formula documentation and getting our new
  release ready. Action formulas have been pushed to our next release.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Judging by the paucity of blog posts lately, you’d be forgiven for thinking that
we’re off on some beach somewhere, sipping margaritas, while essentially letting
Calcapp take care of itself.&lt;/p&gt;

&lt;p&gt;That’s not true, though. We’ve spent many years working full-time on Calcapp,
and this year is no exception. With this blog post, we hereby assert that we are
very much alive and that your precious subscription dollars (or euros, kronor,
or what have you) are being used to dramatically improve Calcapp, and to lay the
foundation for an even better future product.&lt;/p&gt;

&lt;p&gt;We have mostly spent our time on the new formula engine we have teased since
last year (in &lt;a href=&quot;/blog/2021/03/16/status.html&quot;&gt;March&lt;/a&gt;, &lt;a href=&quot;/blog/2021/01/11/ranges.html&quot;&gt;January&lt;/a&gt; and &lt;a href=&quot;/blog/2020/08/12/status.html&quot;&gt;late last
year&lt;/a&gt;). Calcapp will almost reach parity with the latest version of
Microsoft Excel (including its &lt;a href=&quot;https://exceljet.net/glossary/lifting&quot;&gt;new lifting behavior&lt;/a&gt; and functions
like XLOOKUP, FILTER and SORT), and will add well-thought-out Calcapp
extensions.&lt;/p&gt;

&lt;h2 id=&quot;making-a-case-for-improving-our-formula-documentation&quot;&gt;Making a case for improving our formula documentation&lt;/h2&gt;

&lt;p&gt;We first envisioned Calcapp as an app builder for people well-versed in
Microsoft Excel and other spreadsheets. As such, the original &lt;a href=&quot;/blog/2016/05/26/function-browser.html&quot;&gt;function
documentation&lt;/a&gt; was concise to the point of being terse. For a
quick refresher on the order of parameters to the PMT financial function, it
worked nicely, but if you had no idea how to use this function, our
documentation proved inadequate.&lt;/p&gt;

&lt;p&gt;It’s been five and a half years since our beta launched, and we’ve learned a
great deal since then. One of the things we’ve learned is that while some of our
customers indeed are Excel experts, many of you are not. That makes it doubly
important that we have formula documentation that can stand on its own, with no
prior knowledge of Excel necessary.&lt;/p&gt;

&lt;p&gt;Our new formula engine comes with a lot of new formula functions. Like many of
our existing functions, they are compatible with Microsoft Excel. What’s
different, though, is that these functions are often relatively new, meaning
that many of our customers can be expected to be significantly less familiar
with them than with functions that hail from the 1980s. (You may be able to
write SUMIF formulas in your sleep, but can you say the same for XMATCH?)&lt;/p&gt;

&lt;p&gt;We take compatibility with Excel seriously, but at the same time, an app builder
isn’t a spreadsheet, and that must be reflected in its function library. Also,
we think that there is room for improvement in the set of functions offered by
spreadsheets. Our new formula engine offers lots of extensions, with the end
goal being that formulas are easier to write, read and maintain, offer
clearer error messages and require fewer arcane workarounds.&lt;/p&gt;

&lt;p&gt;(For instance, Excel power users typically use the &lt;a href=&quot;https://exceljet.net/the-double-negative-in-excel-formulas&quot;&gt;double
negative&lt;/a&gt; construct with functions like SUMPRODUCT. Calcapp’s
new SUMPRODUCT function will work with or without this construct. Also, Excel’s
new FILTER function requires you to awkwardly use the &lt;code&gt;+&lt;/code&gt; and
&lt;code&gt;*&lt;/code&gt; operators to express “logical or” and “logical and.” Calcapp will
support these operators, but also its own &lt;code&gt;||&lt;/code&gt; and &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;
operators.)&lt;/p&gt;

&lt;h2 id=&quot;a-sneak-peek-at-our-new-formula-documentation&quot;&gt;A sneak peek at our new formula documentation&lt;/h2&gt;

&lt;p&gt;For all the reasons outlined above, we’re investing heavily in our formula
documentation. We shared a preview of our documentation for FILTER &lt;a href=&quot;/blog/2021/03/16/status.html#a-draft-version-of-the-new-filter-function-documentation&quot;&gt;back in
March&lt;/a&gt;, and since then, a lot of improvements have been made:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Readers are looking for a solution to their problem when consulting the
documentation, not an academic treatise. As such, we have reworked it to be
easily scannable, with easily-spotted formula examples, more headings and
shorter paragraphs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Our new formula engine will support decimal commas and not just decimal points
(enabling the formula &lt;code&gt;SUM(3.14, 2.72)&lt;/code&gt; to be written as
&lt;code&gt;SUM(3,14; 2,72)&lt;/code&gt;). You’ll be able to view all example formulas
using either style, making it possible to copy and paste examples directly to
Calcapp Creator regardless of your decimal separator preference.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We have written several thousand formula examples. These example formulas
range from straight-forward invocations of your favorite functions to advanced
function combinations. All examples come with a button for copying the example
formulas to the clipboard.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The sidebar of the Learn section of our website has been modernized to work
better on mobile devices. It can now be brought up at any point by clicking
the menu button in the header.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Function and operator details—like parameters, the return value and their
types—are now hidden by default. We think that most readers are better served
by being presented with examples before possibly digging into the details
later. Also, the types in our documentation (whether a parameter is a number
or a text string, for instance) have been simplified.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The new documentation contains a massive number of links. When a formula
example makes use of a function or operator that is different from the one you
are reading about, simply click the link to be taken to documentation that
explains the function or operator.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;All formula examples have been carefully proofread, manually and through a
special program we wrote that asked Calcapp itself to verify that they are
correct. Not only that, we wrote a separate program which automatically turned
our documentation into a Calcapp app, including all the calculated results, as
calculated by the app. It’s important that you can trust our documentation and
our examples to be correct, and we have gone the extra mile to ensure that
this is so.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a screenshot of the documentation for FILTER:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2021-07-01-status/filter.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2021-07-01-status/filter.png&quot; alt=&quot;A revised version of our new FILTER documentation&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;When we completed revamping our function and operator documentation, we realized
that we wanted our property documentation to be equally good. (What’s a
property? Fields have lots of them, and they represent things like the value of
the field, whether it is visible and its color. What sets Calcapp apart is that
these properties can be defined through formulas, making for truly dynamic user
interfaces adapting to the actions of your users.)&lt;/p&gt;

&lt;p&gt;That’s where we are today, moving our existing property documentation to our
main website, and expanding it in the process with lots of new formula
examples. We expect this process to be faster than writing and copy-editing the
function and operator documentation.&lt;/p&gt;

&lt;p&gt;Earlier posts have discussed our new support for &lt;a href=&quot;https://www.calcapp.net/blog/2020/04/02/calcapp-4.html#action-formulas&quot;&gt;action
formulas&lt;/a&gt;. In order to get our new release out the door sooner,
we have decided to push this important feature to the next release. All the
groundwork for action formulas has already been laid, we just need some extra
time to really make this feature shine.&lt;/p&gt;

&lt;p&gt;We had wanted to release our new version before the summer holidays. We could
probably still make it, but we think it would be ill-advised. We prize stability
over everything else, to ensure that your apps continue working, no matter what.
We don’t want to jeopardize stability by pushing out an ambitious new release
when the core team is on a much-needed break.&lt;/p&gt;

&lt;p&gt;Look for our new release in the coming months.&lt;/p&gt;

</description>
        <pubDate>Thu, 01 Jul 2021 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/07/01/status.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/07/01/status.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Decimal commas in formulas and better documentation are coming soon</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Our next release will add a brand new formula engine, which will support
  decimal commas in addition to decimal points in formulas. It will also come
  with much-improved formula documentation and more than 100 new functions.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;In our &lt;a href=&quot;/blog/2021/01/11/ranges.html&quot;&gt;last post&lt;/a&gt; in January, we shared an update on our new formula
engine, which will support arrays, ranges and lots of new functions. We closed
by writing that we hoped that our new release would “see the light of day in
March.”&lt;/p&gt;

&lt;p&gt;The bad news is that our next release will take a little longer to reach you.
The good news is that we’re pushing back the release for a good reason: we want
to get two additional features done, which we think will make your day-to-day
work with Calcapp easier.&lt;/p&gt;

&lt;p&gt;Those features are &lt;strong&gt;support for decimal commas in formulas&lt;/strong&gt; and
&lt;strong&gt;much-improved formula documentation&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;decimal-commas-in-formulas&quot;&gt;Decimal commas in formulas&lt;/h2&gt;

&lt;p&gt;Since its inception, Calcapp has only recognized decimal points (“.”) as decimal
separators and commas (“,”) as parameter separators in formulas. This is in line
with how numbers are written in countries like the US, Britain, Australia, New
Zeeland, China, Japan, India and parts of Africa.&lt;/p&gt;

&lt;p&gt;However, most parts of South America and Europe (including Russia), as well as
parts of Africa, use decimal commas, making Calcapp formulas feel foreign in
these countries. We often stress that you can frequently carry over formulas
from spreadsheets to Calcapp simply by &lt;a href=&quot;/blog/2017/06/14/convert.html&quot;&gt;copying and pasting them&lt;/a&gt;, but
this has sadly not worked well for our European and South American customers.&lt;/p&gt;

&lt;p&gt;Apps produced with Calcapp have supported languages other than US English &lt;a href=&quot;/blog/2018/03/06/locales.html&quot;&gt;for
more than three years now&lt;/a&gt;. Numbers are formatted according to the
language of the app and functions like PARSENUMBER and FORMATNUMBER correctly
handle the decimal separator of the configured language. In other words, apps
have handled decimal commas correctly for years now, but not the app designer.&lt;/p&gt;

&lt;p&gt;Programming languages typically use decimal points exclusively. Spreadsheets,
however, with very few exceptions either allow the decimal separator to be set
manually or follow the conventions of the host operating system. Spreadsheets
that use decimal commas as decimal separators typically use semicolons (“;”) as
parameter separators instead of commas.&lt;/p&gt;

&lt;p&gt;Ironically, we’re a Swedish business, and decimal commas are exclusively used as
decimal separators here. We’re not only Swedish, though, we’re also software
developers. As programming languages exclusively support decimal points, it
appears that we have grown a little too comfortable with decimal points to
realize that this has been a major pain point our customers have experienced.&lt;/p&gt;

&lt;p&gt;Enough is enough. We’re currently working on supporting decimal commas natively
in formulas. There will be a preference you’ll be able to toggle, which will
then make all formulas you edit use decimal commas as decimal separators instead
of decimal points. This means that you’ll soon be able to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(Field1 &amp;gt;=
3.14, 1.23)&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(Field1 &amp;gt;= 3,14; 1.23)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Calcapp 4 formula engine actually introduces another separator which is
affected by this change, in addition to decimal and parameter separators:
&lt;em&gt;statement separators&lt;/em&gt;. As mentioned &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;elsewhere&lt;/a&gt;, we’ll soon support
&lt;em&gt;action formulas&lt;/em&gt;, which you’ll be able to associate with buttons. When a button
is activated, the formula is run, and these formulas will be able to execute
multiple actions (or “statements”), like sending multiple reports and
conditionally resetting fields.&lt;/p&gt;

&lt;p&gt;To separate actions, or statements, you’ll need to use a statement separator.
If Calcapp Creator is configured to use a decimal point, that’s a semicolon:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(Field1 &amp;gt;= 3.14, RESET(Field1)); ALERT(&quot;Done!&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This example resets &lt;em&gt;Field1&lt;/em&gt; only if its value is greater than or equal to 3.14.
It then (unconditionally) displays the message “Done!” in a popup box. The two
statements are separated by a semicolon.&lt;/p&gt;

&lt;p&gt;If Calcapp is configured to use a decimal point, you instead need to write two
semicolons:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(Field1 &amp;gt;= 3,14; RESET(Field1));; ALERT(&quot;Done!&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;much-improved-function-documentation&quot;&gt;Much-improved function documentation&lt;/h2&gt;

&lt;p&gt;Back in 2016, we overhauled our formula engine, tweaking &lt;a href=&quot;/blog/2016/06/02/formula-syntax.html&quot;&gt;the way you write
formulas&lt;/a&gt; slightly—to improve compatibility with
spreadsheets—and added support for hundreds of spreadsheet functions. Overnight,
we went from supporting around &lt;a href=&quot;/blog/2015/12/10/status.html#the-beginnings-of-a-help-system&quot;&gt;20 functions&lt;/a&gt; to &lt;a href=&quot;/blog/2016/05/25/244-functions.html&quot;&gt;supporting
244&lt;/a&gt;. (Today, that number is 281.)&lt;/p&gt;

&lt;p&gt;We knew that we needed documentation—for the functions themselves as well as
their parameters—but writing high-quality documentation for hundreds of
functions is not an easy task, and hard to justify for a product that was then
in beta and hadn’t quite found its market yet. As a result, the documentation
we did produce was quite terse.&lt;/p&gt;

&lt;p&gt;Times have changed. The new functions we are adding can be used in many ways,
and there may be alternatives to them that are preferable in some contexts. As a
result, they need examples and room for a comprehensive discussion section.&lt;/p&gt;

&lt;p&gt;We have re-written or expanded the documentation for most functions. There are
exceptions, though. We have done little to change the documentation for most of
the specialized statistical and financial functions we offer (like GAMMA.DIST,
which still only “calculates values for a Gamma distribution,” with no
additional content). All functions, except for compatibility functions, have at
least one example, though.&lt;/p&gt;

&lt;p&gt;The new documentation is far too voluminous to fit in the old reference sidebar.
The plan is to host the documentation on the main website, and only include the
first sentence and the parameter documentation in the reference sidebar. The
full documentation will then be available from the sidebar through a link.&lt;/p&gt;

&lt;p&gt;An added benefit of having the documentation available on the main website will
be that you’ll more easily be able to make hard copies of it. Search engines
will also have an easier time finding it.&lt;/p&gt;

&lt;p&gt;To illustrate our new approach to documentation, the next section is a draft
copy of our documentation for the new FILTER function.&lt;/p&gt;

&lt;h2 id=&quot;a-draft-version-of-the-new-filter-function-documentation&quot;&gt;A draft version of the new FILTER function documentation&lt;/h2&gt;

&lt;p&gt;Filters the first array using the second parameter. For instance, &lt;code&gt;FILTER({
1, 2, 3 }, { FALSE, TRUE, TRUE })&lt;/code&gt; returns &lt;code&gt;{ 2, 3 }&lt;/code&gt;. 1 is not
part of the returned array, as the corresponding element in the second array is
FALSE. 2 and 3 are both part of the returned array, as the corresponding
elements in the second array are both TRUE.&lt;/p&gt;

&lt;p&gt;In other words, the returned array contains an element found in the first array
only if the corresponding element in the second array is TRUE. The two arrays
must be equal in size.&lt;/p&gt;

&lt;p&gt;The second array is often not provided explicitly. Rather, an operation is
typically used that returns a logical array. For instance,
&lt;code&gt;FILTER(Field1:Field3, Field1:Field3 &amp;gt; 5)&lt;/code&gt; returns fields whose
values are greater than 5.&lt;/p&gt;

&lt;p&gt;(The &lt;code&gt;Field1:Field3&lt;/code&gt; range is a short-hand way of expressing an array
containing &lt;em&gt;Field1&lt;/em&gt; and &lt;em&gt;Field3&lt;/em&gt;, as well as any fields that
appear between them, such as &lt;em&gt;Field2&lt;/em&gt;. If only &lt;em&gt;Field2&lt;/em&gt; appears
between the other two fields, &lt;code&gt;Field1:Field3&lt;/code&gt; and &lt;code&gt;{ Field1,
Field2, Field3 }&lt;/code&gt; are equivalent.)&lt;/p&gt;

&lt;p&gt;The second array does not need to reference the same array as the first array.
&lt;code&gt;FILTER({ &quot;Sally&quot;, &quot;Ed&quot;, &quot;Luke&quot;, &quot;Jenny&quot; }, { 90, 62, 91, 82 } &amp;gt;
85)&lt;/code&gt;, where the first array contains student names and the second array
contains their test scores, returns an array of names of the students who scored
more than 85.&lt;/p&gt;

&lt;p&gt;Use the SIZE function to determine the number of elements returned by FILTER.
&lt;code&gt;SIZE(FILTER(Field1:Field100, Item &amp;gt; 5))&lt;/code&gt; returns the number of
fields, in the &lt;code&gt;Field1:Field100&lt;/code&gt; range, whose values are greater than
5.&lt;/p&gt;

&lt;h3&gt;Combining multiple conditions&lt;/h3&gt;
&lt;p&gt;Use the logical operators &lt;code&gt;||&lt;/code&gt; to express “logical or” (disjunction)
and &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; to express “logical and” (conjunction).
&lt;code&gt;FILTER(Field1:Field3, (Field1:Field3 &amp;gt; 5) || (Field1:Field3 &amp;lt;
2))&lt;/code&gt; returns those fields whose values are greater than 5 or less than 2.
&lt;code&gt;FILTER(Field1:Field3, (Field1:Field3 &amp;gt; 5) &amp;amp;&amp;amp;
ISODD(Field1:Field3))&lt;/code&gt; returns only those fields whose values are both
greater than 5 and are odd numbers.&lt;/p&gt;

&lt;p&gt;Traditionally, spreadsheets use the &lt;code&gt;+&lt;/code&gt; operator to express “or” and
the &lt;code&gt;*&lt;/code&gt; operator to express “and.” Calcapp supports these operators
too. (The functions OR and AND cannot be used in this context, as they return a
single logical value, not a logical array.)&lt;/p&gt;

&lt;h3&gt;Using a formula fragment to filter elements&lt;/h3&gt;
&lt;p&gt;Instead of passing a logical array as the second parameter, you can also use a
formula fragment which is expected to return TRUE if the element should be
included and FALSE otherwise. &lt;code&gt;FILTER({ 1, 2, 3 }, { 1, 2, 3 } &amp;gt;
1)&lt;/code&gt; can also be expressed as &lt;code&gt;FILTER({ 1, 2, 3 }, Item &amp;gt;
1)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The formula fragment you supply as the second parameter is run once per element.
The element can be accessed as the &lt;code&gt;Item&lt;/code&gt; value. Moreover, the index
of the element (1 for the first element, 2 for the second element, etc) can be
accessed as the &lt;code&gt;Index&lt;/code&gt; value and the source array—given as the first
parameter to FILTER—as the &lt;code&gt;Source&lt;/code&gt; value. Including only the last
three elements can be achieved using a formula like this one:
&lt;code&gt;FILTER(SEQUENCE(100), Index &amp;gt; SIZE(Source) - 3)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This variant is useful if you need to compare array elements only against
themselves. It has the benefit of saving you from having to repeat the source
array in the formula. This feature is specific to Calcapp and is not found in
spreadsheets.&lt;/p&gt;

&lt;p&gt;(Using this variant when you need to examine another array is possible, but is
not as convenient. &lt;code&gt;FILTER({ &quot;Sally&quot;, &quot;Ed&quot;, &quot;Luke&quot;, &quot;Jenny&quot; }, { 90, 62,
91, 82 } &amp;gt; 85)&lt;/code&gt; would be expressed as &lt;code&gt;FILTER({ &quot;Sally&quot;, &quot;Ed&quot;,
&quot;Luke&quot;, &quot;Jenny&quot; }, INDEX({ 90, 62, 91, 82 }, Index) &amp;gt; 85)&lt;/code&gt;, using the
&lt;code&gt;Index&lt;/code&gt; value together with the INDEX function to extract the correct
value from the other array.)&lt;/p&gt;

&lt;h3&gt;Using FILTER instead of the *IF functions&lt;/h3&gt;
&lt;p&gt;When combined with other functions, FILTER can be used as a replacement for
functions like AVERAGEIF, COUNTIF and SUMIF. These functions all boil down to
filtering an array before applying an additional operation.&lt;/p&gt;

&lt;p&gt;SUMIF, for instance, first filters an array based on a condition and then adds
the resulting numbers together, returning the result. &lt;code&gt;SUMIF({ 1, 10, 100,
1000 }, &quot;&amp;gt;25&quot;)&lt;/code&gt; returns 1100, because only 100 and 1000 are greater
than 25. &lt;code&gt;SUM(FILTER({ 1, 10, 100, 1000 }, Item &amp;gt; 25))&lt;/code&gt; and
&lt;code&gt;SUM(FILTER({ 1, 10, 100, 1000 }, { 1, 10, 100, 1000 } &amp;gt; 25))&lt;/code&gt;
return the same result.&lt;/p&gt;

&lt;p&gt;Similarly, &lt;code&gt;COUNTIF({ 1, 10, 100, 1000 }, &quot;&amp;gt;25&quot;)&lt;/code&gt; returns 2,
because exactly two array elements are greater than 25. &lt;code&gt;SIZE(FILTER({ 1,
10, 100, 1000 }, Item &amp;gt; 25))&lt;/code&gt; is equivalent—the FILTER invocation
returns &lt;code&gt;{ 100, 1000 }&lt;/code&gt; and SIZE returns the size of that array, 2.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AVERAGEIF({ 1, 10, 100, 1000 }, &quot;&amp;gt;25&quot;)&lt;/code&gt; returns 550, because that
is the average value between 100 and 1000. &lt;code&gt;AVERAGE(FILTER({ 1, 10, 100,
1000 }, Item &amp;gt; 25))&lt;/code&gt; is equivalent.&lt;/p&gt;

&lt;p&gt;When given a third parameter, AVERAGEIF, COUNTIF and SUMIF apply the condition
to the first array, while applying the operation (averaging, counting and
summing) to the first array. &lt;code&gt;SUMIF({ &quot;Dave&quot;, &quot;Sally&quot;, &quot;Sally&quot; }, &quot;Sally&quot;,
{ 30, 40, 50 })&lt;/code&gt; adds together 40 and 50, but not 30, as these numbers are
associated with the text string “Sally”, which the condition stipulates. The
equivalent formula using FILTER is &lt;code&gt;SUM(FILTER({ 30, 40, 50 }, { &quot;Dave&quot;,
&quot;Sally&quot;, &quot;Sally&quot; } = &quot;Sally&quot;))&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Using FILTER instead of the *IFS functions&lt;/h3&gt;
&lt;p&gt;AVERAGEIF, COUNTIF and SUMIF also come in versions designed to be used with
multiple conditions: AVERAGEIFS, COUNTIFS and SUMIFS. There are also two *IFS
functions with no *IF counterpart: MINIFS and MAXIFS, which return the smallest
and largest number, respectively, from an array, provided that a number of
conditions are met.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AVERAGEIFS({ 90, 62, 91, 82 }, { &quot;F&quot;, &quot;M&quot;, &quot;M&quot;, &quot;F&quot; }, &quot;F&quot;, { &quot;CA&quot;, &quot;CA&quot;,
&quot;AZ&quot;, &quot;AK&quot; }, &quot;AK&quot;)&lt;/code&gt; returns an average of the test scores obtained by
female students who reside in Arkansas (abbreviated “AK”). Here, only one test
score matches (82) and is returned, because while two female students appear in
the data, only one of the students resides in Arkansas.&lt;/p&gt;

&lt;p&gt;The equivalent formula using FILTER is &lt;code&gt;AVERAGE(FILTER({ 90, 62, 91, 82 },
({ &quot;F&quot;, &quot;M&quot;, &quot;M&quot;, &quot;F&quot; } = &quot;F&quot;) &amp;amp;&amp;amp; ({ &quot;CA&quot;, &quot;CA&quot;, &quot;AZ&quot;, &quot;AK&quot; } =
&quot;AK&quot;)))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The FILTER version is far more versatile. AVERAGEIFS can only be used with
“logical and” and not “logical or” (or any other combination of logical
operations). What if we want the average of all test scores associated either
with female students or students residing in Arkansas? AVERAGEIFS does not
provide this feature, but using FILTER, it’s as easy as turning
&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; into &lt;code&gt;||&lt;/code&gt;: &lt;code&gt;AVERAGE(FILTER({ 90, 62, 91,
82 }, ({ &quot;F&quot;, &quot;M&quot;, &quot;M&quot;, &quot;F&quot; } = &quot;F&quot;) || ({ &quot;CA&quot;, &quot;CA&quot;, &quot;AZ&quot;, &quot;AK&quot; } =
&quot;AK&quot;)))&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;FILTER, MAP and REDUCE&lt;/h3&gt;
&lt;p&gt;FILTER, MAP and REDUCE are commonly used together, as a data processing pipeline
to transform data. FILTER is used to remove irrelevant elements from an array,
MAP is used to transform the remaining elements and REDUCE, finally, is used to
transform the resulting array to a single value.&lt;/p&gt;

&lt;p&gt;Instead of REDUCE, a simpler function can be used which reduces an array of
values to a single value. The most popular such functions are SUM (which adds
all array elements together and returns the result) and AVERAGE (which returns
an average of all the array elements).&lt;/p&gt;

&lt;p&gt;A single formula can use multiple invocations of MAP and FILTER. For instance,
an innermost FILTER invocation can filter the raw array once, and then hand this
data to MAP, which transforms the filtered data. This data can then, once more,
be given to FILTER, which filters out additional elements, and so.&lt;/p&gt;

&lt;p&gt;The formula &lt;code&gt;SUM(FILTER(MAP(FILTER({ &quot;$326.60&quot;, &quot;€402.80&quot;, &quot;$290.00&quot;,
&quot;$128&quot;, &quot;3002 SEK&quot; }, STARTSWITH(Item, &quot;$&quot;)), PARSENUMBER(Item)), Item &amp;gt;
200))&lt;/code&gt; starts off with the text array &lt;code&gt;{ &quot;$326.60&quot;, &quot;€402.80&quot;,
&quot;$290.00&quot;, &quot;$128&quot;, &quot;3002 SEK&quot; }&lt;/code&gt;, listing amounts in various currencies.
Working our way outwards from the array, FILTER is then applied to the array,
and uses the formula fragment &lt;code&gt;STARTSWITH(Item, &quot;$&quot;)&lt;/code&gt; to only include
array elements which start with a dollar sign. That leaves &lt;code&gt;{ &quot;$326.60&quot;,
&quot;$290.00&quot;, &quot;$128&quot; }&lt;/code&gt;. MAP is applied to this array, with the formula
fragment &lt;code&gt;PARSENUMBER(Item)&lt;/code&gt;, which converts the text array with
textual amounts to a number array holding the same amounts: &lt;code&gt;{ 326.6, 290,
128 }&lt;/code&gt;. FILTER is then applied to this array using this formula fragment,
&lt;code&gt;Item &amp;gt; 200&lt;/code&gt;, which filters out all elements which are not greater
than 200. That leaves the array &lt;code&gt;{ 326.6, 290 }&lt;/code&gt;. Finally, SUM is
applied to this array, returning the grand total 616.60.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;values&lt;/code&gt; the values to filter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;inclusions&lt;/code&gt; either an array or a formula fragment. If this parameter
is an array, it should be a logical array with the same size as the array of
values to filter. The returned array only contains values where the
corresponding element in this array is TRUE. If this parameter is a formula
fragment, it is run once per array element and is expected to return TRUE only
if the corresponding array element should be included in the returned array. To
do its work, it has access to the three named values &lt;code&gt;Item&lt;/code&gt;, the
array element under consideration, &lt;code&gt;Index&lt;/code&gt;, the index of the array
element (1 for the first element, 2 for the second element, etc) and finally
&lt;code&gt;Source&lt;/code&gt;, which is a reference to the array to filter, given as the
first parameter to FILTER.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fallbackValues&lt;/code&gt; the values to return if no values matched the
filter. If there are no fallback values, an empty array is returned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;
a filtered version of the given values. If no values match the filter, an empty
array is returned, unless the &lt;code&gt;fallbackValues&lt;/code&gt; parameter is provided,
in which case those values are returned instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;FILTER({ 1, 2, 3 }, { FALSE, TRUE, TRUE })&lt;/pre&gt;
&lt;p&gt;returns &lt;code&gt;{ 2, 3 }&lt;/code&gt;. 1 is not part of the returned array, as the
corresponding element in the second array is FALSE. 2 and 3 are both part of the
returned array, as the corresponding elements in the second array are both TRUE.&lt;/p&gt;

&lt;pre&gt;FILTER({ 1, 2, 3 }, { 1, 2, 3 } &amp;gt; 1)&lt;/pre&gt;
&lt;p&gt;returns an array containing the elements which are greater than one, &lt;code&gt;{ 2,
3 }&lt;/code&gt;. &lt;code&gt;{ 1, 2, 3 } &amp;gt; 1&lt;/code&gt; returns the logical array &lt;code&gt;{
FALSE, TRUE, TRUE }&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;FILTER({ 1, 2, 3 }, Item &amp;gt; 1)&lt;/pre&gt;
&lt;p&gt;returns an array containing the elements which are greater than one, &lt;code&gt;{ 2,
3 }&lt;/code&gt;. This variant uses a formula fragment, which is run once per array
element to determine whether the element should be part of the result. The
formula fragment is expected to return TRUE if that is the case.&lt;/p&gt;

&lt;pre&gt;SIZE(FILTER({ 1, 2, 3 }, Item &amp;gt; 1))&lt;/pre&gt;
&lt;p&gt;returns the number of array elements which are greater than one. As only 2 and 3
are greater than 1, 2 is returned. This variant uses a formula fragment, which
is run once per array element to determine whether the element should be part of
the result. The formula fragment is expected to return TRUE if that is the case.&lt;/p&gt;

&lt;pre&gt;FILTER({ 1, 2, 3 }, V -&amp;gt; V &amp;gt; 1)&lt;/pre&gt;
&lt;p&gt;returns an array containing the elements which are greater than one, &lt;code&gt;{ 2,
3 }&lt;/code&gt;. This variant uses a formula fragment, which is run once per array
element to determine whether the element should be part of the result. The
formula fragment is expected to return TRUE if that is the case. This fragment
renames the &lt;code&gt;Item&lt;/code&gt; value, which references the array element under
consideration, to V. For longer formula fragments, renaming a value can make the
resulting formula fragment much smaller. Alternatively, renaming a value can be
used to give it a name that more accurately describes the value.&lt;/p&gt;

&lt;pre&gt;FILTER({ 10, 20, 30 }, Index &amp;gt;= 3)&lt;/pre&gt;
&lt;p&gt;returns &lt;code&gt;{ 3 }&lt;/code&gt;, as only the last array element has an index greater
than or equal to 3. (The first element has an index of 1, the second an index of
2, etc.)&lt;/p&gt;

&lt;pre&gt;FILTER({ 10, 20, 30 }, (V, I) -&amp;gt; I &amp;gt;= 3)&lt;/pre&gt;
&lt;p&gt;returns &lt;code&gt;{ 3 }&lt;/code&gt;, as only the last array element has an index greater
than or equal to 3. (The first element has an index of 1, the second an index of
2, etc.) Here, both the &lt;code&gt;Item&lt;/code&gt; and &lt;code&gt;Index&lt;/code&gt; values are
renamed to &lt;code&gt;V&lt;/code&gt; and &lt;code&gt;I&lt;/code&gt;, respectively. Even if the
&lt;code&gt;Item&lt;/code&gt; value is not needed, it still needs to be renamed, as it
appears before the &lt;code&gt;Index&lt;/code&gt; value.&lt;/p&gt;

&lt;pre&gt;FILTER({ 10, 20, 35 }, MOD(Item, 10) = 0)&lt;/pre&gt;
&lt;p&gt;returns array elements which are evenly divisible by 10, meaning that &lt;code&gt;{
10, 20 }&lt;/code&gt; is returned.&lt;/p&gt;

&lt;pre&gt;FILTER({ 10, 20, 35 }, MOD(Item, Field1) = 0)&lt;/pre&gt;
&lt;p&gt;returns all array elements which are evenly divisible by
&lt;code&gt;Field1.Value&amp;lt;/em&amp;gt;, provided by the user.&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;FILTER({ 10, 20, 35 }, MOD(Item, 50) = 0)&lt;/pre&gt;
&lt;p&gt;returns array elements which are evenly divisible by 50. As there are no such
array elements, an empty array is returned.&lt;/p&gt;

&lt;pre&gt;FILTER({ 10, 20, 35 }, MOD(Item, 50) = 0, { -50 })&lt;/pre&gt;
&lt;p&gt;returns array elements which are evenly divisible by 50. As there are no such
array elements, the third parameter is returned, &lt;code&gt;{ -50 }&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;FILTER({ &quot;Sally&quot;, &quot;Luke&quot;, &quot;Jenny&quot; }, { 90, 91, 82 } &amp;gt; 85)&lt;/pre&gt;
&lt;p&gt;returns &lt;code&gt;{ &quot;Sally&quot;, &quot;Luke&quot; }&lt;/code&gt;, which are the names of the students
who scored higher than 85, provided that the first array contains student names
and the second array contains their scores.&lt;/p&gt;

&lt;pre&gt;FILTER({ Field1, Field2 }.Color, { Field1, Field2 } &amp;gt; 3)&lt;/pre&gt;
&lt;p&gt;returns the colors of the fields whose values are greater than 3 as an array.&lt;/p&gt;

&lt;pre&gt;FILTER(Field1:Field100.Color, Field1:Field100 &amp;gt; 3)&lt;/pre&gt;
&lt;p&gt;returns the colors of the fields whose values are greater than 3 as an array.
&lt;code&gt;Field1:Field100&lt;/code&gt; is short-hand for an array which includes
&lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field100&lt;/em&gt; and all other fields which appear between
them.&lt;/p&gt;

&lt;pre&gt;FILTER(Field1:Field100.Value, MOD(Index, 5) = 0)&lt;/pre&gt;
&lt;p&gt;returns the values of every fifth field, among those listed.
&lt;code&gt;Field1:Field100&lt;/code&gt; is short-hand for an array which includes
&lt;em&gt;Field1&lt;/em&gt;, &lt;em&gt;Field100&lt;/em&gt; and all other fields which appear between
them.&lt;/p&gt;

&lt;pre&gt;SORT(UNIQUE(FILTER({ 32, 8, 8, 16, 4, 2, 1 }, Item &amp;gt; 7)))&lt;/pre&gt;
&lt;p&gt;returns &lt;code&gt;{ 8, 16, 32 }&lt;/code&gt;, which includes only those elements of the
&lt;code&gt;{ 32, 8, 8, 16, 4, 2, 1 }&lt;/code&gt; array which are greater than 7. UNIQUE
ensures that there are no duplicate values, and SORT ensures that the returned
array is sorted.&lt;/p&gt;

&lt;h2 id=&quot;current-status&quot;&gt;Current status&lt;/h2&gt;

&lt;p&gt;We’re currently implementing support for commas as decimal separators in
formulas. The new formula documentation has already been written. It has not yet
been proof-read, though, nor have we written the software which will generate
HTML documentation for the main website. (Should there be a search field? Should
one page be generated for every function, or one page per category, which would
group all text functions together? There are a few questions to resolve here.)&lt;/p&gt;

&lt;p&gt;There are also many new button types (which will be able to do things like
execute action formulas and open the system map app). They have not yet been
implemented, but are not expected to be time-consuming.&lt;/p&gt;

&lt;p&gt;We also need to ensure that the migration process is smooth, and that all paid
apps will continue to run with no interruptions once the new formula engine is
live.&lt;/p&gt;

&lt;p&gt;This will be one of the biggest Calcapp upgrades we have ever released, and
without a doubt the biggest update our formula engine has ever received. We’re
anxious to get it into your hands and we look forward to seeing the amazing apps
you’ll create with it.&lt;/p&gt;

</description>
        <pubDate>Tue, 16 Mar 2021 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/03/16/status.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/03/16/status.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Array ranges, SUMIF and more are coming soon</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Ranges will enable authors to easily and concisely refer to multiple values in
  formulas. Ranges, combined with the new function SUMIF, will make
  conditionally summing values much easier than before.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;&lt;span class=&quot;formula decimalpoint&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;span class=&quot;formula decimalcomma&quot;&gt;1 &lt;span class=&quot;binaryOperator&quot; name=&quot;ADDITION&quot;&gt;+&lt;/span&gt; 2&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;We have supported formula functions like SUM and PRODUCT &lt;a href=&quot;/blog/2016/05/25/244-functions.html&quot;&gt;for a long time
now&lt;/a&gt;. What they have in common is that you supply multiple
parameters and get a single result back.&lt;/p&gt;

&lt;p&gt;These formula functions are used frequently by Calcapp authors, but provide
little value beyond adding or multiplying numbers together using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;.
The formulas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(Field1, 4)&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1 + 4&lt;/code&gt; do the exact same thing, which is
also true for the formulas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PRODUCT(4, 8, 16)&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4 * 8 * 16&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Functions like SUM and PRODUCT are about to become significantly more useful,
though, with the introduction of &lt;em&gt;ranges&lt;/em&gt;. If you have more than a passing
familiarity with spreadsheets like Microsoft Excel, you have definitely
encountered ranges (whether or not you know them by that name).&lt;/p&gt;

&lt;p&gt;In Excel, if cells A1 through A5 contain values you want to add together, you
can easily do so using the formula &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=SUM(A1:A5)&lt;/code&gt;. By contrast, Calcapp has
historically forced you to enumerate all the values you wanted to add together,
by writing something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(A1, A2, A3, A4, A5)&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1 + A2 + A3 + A4 + A5&lt;/code&gt;.
(Calcapp doesn’t require you to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt; before formulas.) Compared to using
ranges, that’s a lot more work.&lt;/p&gt;

&lt;p&gt;The good news is that our upcoming release will support ranges. If you have five
number fields named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A2&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A3&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A4&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A5&lt;/code&gt; (appearing one after
another), adding their values together will be as easy as using the formula
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(A1:A5)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Calcapp authors don’t typically name their fields as though they were cells in a
spreadsheet grid. Rather, fields are automatically named using their labels as a
guide, so if you use the label “Maximum weight” for a field, the field is
assigned the name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MaximumWeight&lt;/code&gt; automatically. (To break the association
between the label and the name, simply type a new name manually in the name
field, to the left of the formula bar.) As such, ranges in Calcapp formulas will
typically look more like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(MaximumWeight:IndividualWeight)&lt;/code&gt; than
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(A1:A5)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The formula &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(MaximumWeight:IndividualWeight)&lt;/code&gt; will add all values together
that belong to not only the fields &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MaximumWeight&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndividualWeight&lt;/code&gt;, but
all fields that appear between them in the app designer.&lt;/p&gt;

&lt;h2 id=&quot;under-the-hood&quot;&gt;Under the hood&lt;/h2&gt;

&lt;p&gt;In a spreadsheet, the cell reference &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1&lt;/code&gt; refers to the cell in the first column
and the first row of the spreadsheet grid and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A2&lt;/code&gt; refers to the cell in the
first column and the second row. The range &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1:A2&lt;/code&gt; refers to both of these
cells.&lt;/p&gt;

&lt;p&gt;Spreadsheets also support something called &lt;em&gt;arrays&lt;/em&gt;, which are similar to ranges
in that they hold multiple values. An &lt;em&gt;array constant&lt;/em&gt; in a spreadsheet is
written between curly brackets, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ 2, 4 }&lt;/code&gt;, which is a value holding the
values 2 and 4. (&lt;a href=&quot;/blog/2020/08/12/status.html&quot;&gt;As we have discussed earlier in this space&lt;/a&gt;,
we are adding support for arrays to Calcapp.)&lt;/p&gt;

&lt;p&gt;Ranges and arrays are subtly different in spreadsheets. In Calcapp, there is no
spreadsheet grid, so a range and an array are one and the same. If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field2&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field3&lt;/code&gt; appear one after the other in the app designer, the
formulas &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(Field1:Field3)&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM({ Field1, Field2, Field3 })&lt;/code&gt; not only
return the same result, they look roughly identical to Calcapp. As such, a range
is simply a more concise way of writing an array.&lt;/p&gt;

&lt;h2 id=&quot;an-example&quot;&gt;An example&lt;/h2&gt;

&lt;p&gt;What if you have five fields (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1&lt;/code&gt; through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A5&lt;/code&gt;, appearing one after the other)
and you want to add their values together, but only those that are greater than
two? This has been possible with Calcapp ever since our first release, but you
had to use a long and cumbersome formula:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(A1 &amp;gt; 2, A1) + IF(A2 &amp;gt; 2, A2) + IF(A3 &amp;gt; 2, A3) + IF(A4 &amp;gt; 2, A4) + IF(A5 &amp;gt; 2,
A5)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;(This formula would become even more unwieldy if you had, say, 100 fields
instead of five.)&lt;/p&gt;

&lt;p&gt;Spreadsheets make this considerably easier. The standard way to solve this is
through the &lt;a href=&quot;https://exceljet.net/excel-functions/excel-sumif-function&quot;&gt;SUMIF&lt;/a&gt; formula function:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF(A1:A5, &quot;&amp;gt;2&quot;)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Calcapp currently supports neither arrays nor ranges, explaining why we haven’t
been able to support the SUMIF function earlier. This issue will be rectified by
our next release, which will add support for not only SUMIF, but also
&lt;a href=&quot;https://exceljet.net/excel-functions/excel-sumifs-function&quot;&gt;SUMIFS&lt;/a&gt;, &lt;a href=&quot;https://exceljet.net/excel-functions/excel-countif-function&quot;&gt;COUNTIF&lt;/a&gt;, &lt;a href=&quot;https://exceljet.net/excel-functions/excel-countifs-function&quot;&gt;COUNTIFS&lt;/a&gt;,
&lt;a href=&quot;https://exceljet.net/excel-functions/excel-averageif-function&quot;&gt;AVERAGEIF&lt;/a&gt;, &lt;a href=&quot;https://exceljet.net/excel-functions/excel-averageifs-function&quot;&gt;AVERAGEIFS&lt;/a&gt;, &lt;a href=&quot;https://exceljet.net/excel-functions/excel-minifs-function&quot;&gt;MINIFS&lt;/a&gt; and
&lt;a href=&quot;https://exceljet.net/excel-functions/excel-maxifs-function&quot;&gt;MAXIFS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As &lt;a href=&quot;/blog/2020/08/12/status.html&quot;&gt;teased earlier&lt;/a&gt;, Calcapp will not only support the formula
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF(A1:A5, &quot;&amp;gt;2&quot;)&lt;/code&gt; (where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;&amp;gt;2&quot;&lt;/code&gt; &lt;em&gt;condition&lt;/em&gt; — determining which values
are considered – is expressed as a text string), but also an alternate form
which can be written like so:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF(A1:A5, Item &amp;gt; 2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The second parameter is technically known as a &lt;em&gt;lambda&lt;/em&gt; (or an &lt;em&gt;anonymous
function&lt;/em&gt;), which returns a logical value (TRUE or FALSE), determining whether a
value should be considered. To help this lambda make this decision, the value
under consideration is available as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Item&lt;/code&gt;. (The name can be changed, but that’s
a topic for another blog post.)&lt;/p&gt;

&lt;p&gt;Lambdas enable you to use complicated logic to determine whether a value should
be considered:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF(A1:A5, (Item &amp;gt; 2) &amp;amp;&amp;amp; (Item &amp;lt; 10) &amp;amp;&amp;amp; ISODD(Item)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The example above only considers values which are greater than two, are less
than ten and are odd. (In other words, only 3, 5, 7 and 9 are considered.)&lt;/p&gt;

&lt;h2 id=&quot;modern-excel-and-dynamic-arrays&quot;&gt;Modern Excel and dynamic arrays&lt;/h2&gt;

&lt;p&gt;One of the most exciting changes to come to Microsoft Excel are &lt;a href=&quot;https://exceljet.net/dynamic-array-formulas-in-excel&quot;&gt;dynamic
arrays&lt;/a&gt;, along with a number of new formula functions. Dynamic
arrays make it much simpler to perform actions like filtering an array
(returning a copy of said array only containing elements satisfying a certain
condition with the FILTER function) and removing duplicates from an array (with
the UNIQUE function).&lt;/p&gt;

&lt;p&gt;We’re happy to announce that we will have full coverage of Microsoft’s new
dynamic array functions when our next release becomes available.&lt;/p&gt;

&lt;p&gt;Let’s return to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF(A1:A5, &quot;&amp;gt;2&quot;)&lt;/code&gt; example above. If you think about it,
there are two things going on here. First, the array consisting of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1:A5&lt;/code&gt;
values is filtered to only contain values that are greater than two. Second,
these values are added together and returned.&lt;/p&gt;

&lt;p&gt;Filtering the array can be accomplished using the new FILTER function, and
summing them can be done using the SUM function. Here’s what that looks like:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(FILTER(A1:A5, A1:A5&amp;gt;2))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;FILTER is asked to filter the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1:A5&lt;/code&gt; range, passed as the first parameter. The
second parameter is also an array, with the same size as the first parameter.
However, it is a logical array, consisting of TRUE and FALSE values. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A1:A5&amp;gt;2&lt;/code&gt;
returns an array consisting of TRUE values where the value is greater than two,
and FALSE values elsewhere. That means that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ 1, 2, 3, 4 }&amp;gt;2&lt;/code&gt; returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ FALSE,
FALSE, TRUE, TRUE }&lt;/code&gt;, because only 3 and 4 are greater than two.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUM(FILTER(A1:A5, A1:A5&amp;gt;2))&lt;/code&gt; may look more cumbersome than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF(A1:A5, &quot;&amp;gt;2&quot;)&lt;/code&gt;
— and it is — but it provides far more flexibility. Which you wind up using
depends on your needs and on your preferences.&lt;/p&gt;

&lt;h2 id=&quot;when-will-this-become-available&quot;&gt;When will this become available?&lt;/h2&gt;

&lt;p&gt;We’re in the last stages of our big formula revamp (which is the first step of
our next-generation &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;Calcapp 4&lt;/a&gt; project). We hope that our next
release, containing these features, will see the light of day in March.&lt;/p&gt;

</description>
        <pubDate>Mon, 11 Jan 2021 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2021/01/11/ranges.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2021/01/11/ranges.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Tip: Share previews of apps</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  When making changes to an app, you often need to share copies of your changed
  app with a small circle of users before letting these changes go live for all
  users. Read this tip to learn how this is done.
&lt;/div&gt;

&lt;p&gt;To make an app available for others to use, you first need to &lt;a href=&quot;/blog/2016/08/01/app-sharing.html&quot;&gt;share
it&lt;/a&gt; by pressing the &lt;strong&gt;Share app&lt;/strong&gt; button in Calcapp Creator:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-10-20-sharing-previews/share-button.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-10-20-sharing-previews/share-button.png&quot; alt=&quot;The Share app button in the top toolbar&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By sharing an app, you create a copy of the app you’re currently working on.
That means that you can continue to work on the app without affecting the shared
version. The shared version will only be updated when you press the button in
the top-right corner (labeled &lt;strong&gt;Update app&lt;/strong&gt; when the app has already been
shared):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-10-20-sharing-previews/update-button.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-10-20-sharing-previews/update-button.png&quot; alt=&quot;The Update app button in the top toolbar&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get an idea of what your app is like to use, without having to update the
shared version, use the preview sidebar by pressing the
&lt;i class=&quot;mdi mdi-play&quot;&gt;&lt;/i&gt; button in the lower-right corner. You can also
browse to &lt;a target=&quot;calcappConnect&quot; href=&quot;https://connect.calcapp.net&quot;&gt;connect.calcapp.net&lt;/a&gt;, on your
desktop computer, tablet or cell phone, to use the development version of your
app.&lt;/p&gt;

&lt;p&gt;This workflow works great if you’re the only person who needs to determine if
your app is ready to be updated. However, most of the time, there are others who
need to chime in as well. These are people whose feedback you may need in order
to determine if the updated version of your app performs well, in terms of its
calculations, grammar and layout.&lt;/p&gt;

&lt;p&gt;In other words, what you’d like to do is share an app with this close circle of
users, without disturbing the app currently being enjoyed by the wider circle of
users. This is something we routinely need when developing our healthcare apps,
which need to be assessed and tested by doctors before the updates go live.&lt;/p&gt;

&lt;p&gt;To achieve this with Calcapp, you need to select &lt;strong&gt;Manage apps…&lt;/strong&gt; from the
main menu (reachable by pressing the &lt;i class=&quot;mdi mdi-menu&quot;&gt;&lt;/i&gt; button in the
upper-right corner):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-10-20-sharing-previews/manage-apps.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-10-20-sharing-previews/manage-apps.png&quot; alt=&quot;The Manage apps window&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, you need to select the app you’d like to share privately. (The app you’re
editing will already be selected for you.) You then need to create a duplicate
of the app, by pressing the &lt;i class=&quot;mdi mdi-chevron-down&quot;&gt;&lt;/i&gt; button and
selecting &lt;strong&gt;Duplicate app&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You’re then given the opportunity to select a new name for the duplicate copy.
As you can see in the image above, we like to include the word “copy” in these
names, along with the date.&lt;/p&gt;

&lt;p&gt;Finally, open the duplicate copy and click &lt;strong&gt;Share app&lt;/strong&gt;. You’ll then get a link
to the duplicate you can share with a small circle of users. When you get
feedback, be sure to make changes to the original app, as opposed to the copy.&lt;/p&gt;

&lt;p&gt;If you need another round of feedback, just repeat this process and create a new
duplicate copy, which you then share. You can remove all these copies when
you’re ready to publish your app.&lt;/p&gt;

&lt;p&gt;Copies of apps are automatically put on a free plan. Apps on a free plan can
only be launched a limited number of times per month (typically, ten). If that
isn’t sufficient, just create a fresh new copy.&lt;/p&gt;

</description>
        <pubDate>Tue, 20 Oct 2020 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/10/20/sharing-previews.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/10/20/sharing-previews.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>Feature: Reset and change your users&apos; passwords</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  You can now reset your users&apos; passwords directly from Calcapp Creator. Use
  this feature if your users have trouble resetting their own passwords or if
  you&apos;d like to set their passwords for them.
&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;/blog/2019/04/12/private-apps.html&quot;&gt;Private apps&lt;/a&gt; require users to sign in before gaining access to
your app. You add and remove users using the Manage users window:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-10-20-password-reset/manage-users-populated.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-10-20-password-reset/manage-users-populated.png&quot; alt=&quot;The Manage users window&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you add a new user and share an app with them, a welcome email is sent
containing a link which enables the user to set an initial password. If the user
forgets their password, they can reset it. That process normally works by
sending an email to the user containing a link the user can use to change the
password.&lt;/p&gt;

&lt;p&gt;Up until now, administrators had no control over this process. An administrator
could add and remove users through Calcapp Creator, but could not change their
users’ passwords or gain access to password reset links. This changes now.&lt;/p&gt;

&lt;p&gt;Why would an administrator need to set a user’s password for them? There are a
number of reasons. First, the password reset email may never arrive at the
destination due to overzealous spam filters. In that case, having access to the
password reset link enables an administrator to send the link to the user
through instant messaging or email. Second, some administrators prefer setting
an initial password for their users instead of sending an automated welcome
email.&lt;/p&gt;

&lt;p&gt;Access this new feature by selecting &lt;strong&gt;Reset user password&lt;/strong&gt; from the main menu
(reachable by pressing the &lt;i class=&quot;mdi mdi-menu&quot;&gt;&lt;/i&gt; button in the
upper-right corner of Calcapp Creator). You’ll then be presented with this new
window:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-10-20-password-reset/reset-password-step-one.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-10-20-password-reset/reset-password-step-one.png&quot; alt=&quot;The Reset password window&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All your users appear in this window. When you press the &lt;strong&gt;Reset password&lt;/strong&gt;
button on the right-hand side, these two buttons appear:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-10-20-password-reset/reset-password-step-two.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-10-20-password-reset/reset-password-step-two.png&quot; alt=&quot;The final step of resetting a user&apos;s password&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you press the &lt;i class=&quot;mdi mdi-rocket&quot;&gt;&lt;/i&gt; button, the password reset link
which ordinarily would have been sent to a user through email is opened in a
separate window, enabling you to set your user’s password directly. If you
instead press the &lt;i class=&quot;mdi mdi-content-copy&quot;&gt;&lt;/i&gt; button, the password
reset link is copied to your clipboard, enabling you to easily send it to your
user.&lt;/p&gt;

</description>
        <pubDate>Tue, 20 Oct 2020 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/10/20/password-reset.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/10/20/password-reset.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Tip: Generate better PDF documents through Zapier</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  PDF reports created with Calcapp will only become truly customizable when
  Calcapp 4 fully arrives. In the meantime, use third-party services through
  Zapier to enable custom-designed PDF documents today.
&lt;/div&gt;

&lt;p&gt;Calcapp has native support for generating PDF reports directly from your app.
These reports can either be &lt;a href=&quot;/blog/2016/10/18/reporting-email.html&quot;&gt;emailed directly&lt;/a&gt; to a list of
recipients (which can be determined using a formula) or be &lt;a href=&quot;/blog/2017/10/29/reporting-download.html&quot;&gt;downloaded directly
to your user’s device&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As things stand, you have very few options for customizing the appearance of
these reports, though. If your requirements include having your logo be part of
the generated report, for instance, or including formatted text, you are
currently out of luck. We have &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html#other-changes&quot;&gt;pledged to create a PDF report
designer&lt;/a&gt; as part of our Calcapp 4 project, but this new
feature will take time to arrive.&lt;/p&gt;

&lt;p&gt;So what do you do if you need this feature today? As luck would have it, Calcapp
can integrate with third-party services, which provide features Calcapp lacks
natively. We have previously described how you can make your app integrate with
the third-party service Zapier to &lt;a href=&quot;/blog/2018/05/18/zapier-video.html&quot;&gt;add rows to a Google Sheets
spreadsheet&lt;/a&gt; when a button in your app is pressed. Other actions
supported by Zapier include sending a message to a Slack channel, tweeting or
creating a new sales lead in Salesforce (and thousands more).&lt;/p&gt;

&lt;p&gt;(We not only support Zapier, but also &lt;a href=&quot;/blog/2019/04/24/json-schema.html&quot;&gt;Microsoft Power Automate&lt;/a&gt;
— previously known as Microsoft Flow — and &lt;a href=&quot;https://www.zoho.com/flow/&quot;&gt;Zoho Flow&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;There are competent third-party solutions for creating PDF files that can
seamlessly integrate with apps you build with Calcapp. We recently had the
opportunity to research this topic and we’ll share our findings in this post.&lt;/p&gt;

&lt;h2 id=&quot;generating-pdf-documents&quot;&gt;Generating PDF documents&lt;/h2&gt;

&lt;p&gt;We have looked at two third-party solutions: &lt;a href=&quot;https://www.webmerge.me/&quot;&gt;Formstack
Documents&lt;/a&gt; (formerly WebMerge) and &lt;a href=&quot;https://docupilot.app/&quot;&gt;Docupilot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From the perspective of Calcapp and the features we need to create custom
reports, both products are fairly similar (though Docupilot is, at the time of
this writing, less expensive). Both ask that you create templates using
graphical WYSIWYG editors (&lt;em&gt;what you see is what you get&lt;/em&gt;), where you insert
special tags which are replaced by the values your users enter in your app. For
instance, if your template contains the text “Hello and welcome, ${Name}!”, and
your app supplies the name Rachel, the generated PDF document will read “Hello
and welcome, Rachel!”.&lt;/p&gt;

&lt;p&gt;This is the template editor in Formstack Documents:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-08-17-zapier-pdf/formstack-documents.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-08-17-zapier-pdf/formstack-documents.png&quot; alt=&quot;Formstack Documents, template editor&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the template editor in Docupilot:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-08-17-zapier-pdf/docupilot.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-08-17-zapier-pdf/docupilot.png&quot; alt=&quot;Docupilot, template editor&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both Formstack Documents and Docupilot can be instructed to send the generated
PDF documents through email, which is likely what you need.&lt;/p&gt;

&lt;p&gt;In order to trigger either service from your app when your users press a button,
use Zapier. In order for Zapier to receive the event from your app, you need the
&lt;em&gt;Webhooks by Zapier&lt;/em&gt; app. (For more information on how to set this up, refer to
&lt;a href=&quot;/blog/2018/05/18/zapier-video.html&quot;&gt;our video tutorial explaining how to use Zapier to integrate your app with
Google Sheets&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Both Formstack Documents and Docupilot are available as apps in Zapier — you
just need to search for them by name. Once you have done so, you need to give
Zapier permission to talk to either service (by copying and pasting a so-called
&lt;em&gt;API key&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;What about your template tags, the ones that should be replaced by values your
users enter in the app? You’ll use Zapier to determine which app fields go with
which tags.&lt;/p&gt;

&lt;p&gt;Let’s consider an app with two fields, &lt;em&gt;Name&lt;/em&gt; and &lt;em&gt;Email&lt;/em&gt; which should be mapped
to the template tags &lt;em&gt;Name&lt;/em&gt; and &lt;em&gt;Email&lt;/em&gt;. This is what this could look like in
Zapier, when used with Formstack Documents:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/media/blog/2020-08-17-zapier-pdf/zapier.png&quot;&gt;
  &lt;img src=&quot;/assets/media/blog/2020-08-17-zapier-pdf/zapier.png&quot; alt=&quot;Zapier when used with Formstack Documents&quot; class=&quot;large-image&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That concludes this whirlwind tour of Formstack Documents and Docupilot, as used
with Calcapp through Zapier. We plan to provide this functionality as a built-in
Calcapp feature in the future, but until then, both Formstack Documents and
Docupilot will get you where you need to go today.&lt;/p&gt;

</description>
        <pubDate>Mon, 17 Aug 2020 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/08/17/zapier-pdf.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/08/17/zapier-pdf.html</guid>
        
        <category>Tip</category>
        
        
      </item>
    
      <item>
        <title>On the road to Calcapp 4</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Calcapp 4 is our next-generation version of Calcapp, and it&apos;s coming along
  nicely. Read on to learn more about the progress we&apos;ve made.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;The time has come to update you on the progress we’ve been making with &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;Calcapp
4&lt;/a&gt;. Be warned, though — this post is somewhat technical. If you
love formulas and what makes them tick, this post is for you. If you’re more
interested in our forthcoming support for customizable PDF reports and binding
fields to data, feel free to skip past the finer details.&lt;/p&gt;

&lt;p&gt;Regardless, rest assured that we’re investing heavily in Calcapp and that we are
committed to bringing you major updates with lots of new useful features.&lt;/p&gt;

&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;Before we get to what we’ve been up to, we’ll take a moment to shine a light on
how Calcapp works. As a Calcapp user, you’re probably familiar with Calcapp
Creator, the app designer, and Calcapp Connect, which you use to run your own
apps as well as shared apps.&lt;/p&gt;

&lt;p&gt;There are other parts of Calcapp, though, which are mostly hidden from view.
There’s Calcapp Server, which is what delivers your apps and allows you to make
updates. Under the hood, it uses something called Calcapp Compiler.&lt;/p&gt;

&lt;p&gt;What’s a compiler? If you’ve ever dabbled in traditional software development,
you know that you sometimes need to &lt;em&gt;compile&lt;/em&gt; code to make it runnable. (With
some languages, such as plain JavaScript, there often isn’t a separate
compilation step, at least not one which is visible to you.) Compilers can
typically tell you of errors in your code, preventing it from becoming runnable.&lt;/p&gt;

&lt;p&gt;Calcapp Compiler does two things. First, it ensures that your app is free of
errors, and if it isn’t, it points out the errors to you. (Have you ever tried
to subtract a number from a text string in a formula? That’s Calcapp Compiler
pointing out the error to you.) Second, it converts (compiles) your Calcapp
formulas to JavaScript code which browsers can run directly.&lt;/p&gt;

&lt;h2 id=&quot;the-progress-weve-been-making&quot;&gt;The progress we’ve been making&lt;/h2&gt;

&lt;p&gt;Calcapp Compiler really is the heart of Calcapp and we have lavished a lot of
attention on it lately. We have, essentially, worked full-time on it since
November, only taking time off for making your apps qualify as &lt;a href=&quot;/blog/2020/04/02/offline.html&quot;&gt;Progressive Web
Apps&lt;/a&gt; and enabling some &lt;a href=&quot;/blog/2020/04/02/release.html&quot;&gt;miscellaneous features&lt;/a&gt;
requested by the community.&lt;/p&gt;

&lt;p&gt;Calcapp formulas are growing up. We’re enabling them to run in response to
events being fired (like a button being pressed). We’re also enabling you to
reference elements of your app directly (and not just field values), which will
come in handy with certain new properties (like a property enabling a formula to
specify which fields to include in a report).&lt;/p&gt;

&lt;p&gt;We’re also adding support for around a hundred new formula functions, including
&lt;a href=&quot;/blog/2020/04/02/calcapp-4.html#support-for-the-switch-formula-function&quot;&gt;SWITCH and IFS&lt;/a&gt;. These functions will replace IF for many uses and make
formulas significantly easier to read and write (without all the matching
parentheses that IF typically requires).&lt;/p&gt;

&lt;p&gt;The most important addition, by far, is support for arrays.&lt;/p&gt;

&lt;h2 id=&quot;supporting-arrays&quot;&gt;Supporting arrays&lt;/h2&gt;

&lt;p&gt;We’ve long talked about adding support for tabular data, and &lt;em&gt;arrays&lt;/em&gt; will be at
the heart of this new support. If you’re not familiar with arrays, think of an
array as a list of items, that is, a single value referencing multiple values.
You can write a literal array in a formula using brackets, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ 2, 4, 6 }&lt;/code&gt;,
which denotes a single array with the ordered values 2, 4 and 6.&lt;/p&gt;

&lt;p&gt;Spreadsheets support both ranges (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B12:C14&lt;/code&gt;) and arrays (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ 2, 4, 6 }&lt;/code&gt;). Some
spreadsheet functions accept both ranges and arrays, some accept only arrays and
some accept only ranges. We find that confusing, so Calcapp will only support
arrays.&lt;/p&gt;

&lt;p&gt;We’re adding support for a very large number of new functions, with the vast
majority of these expecting arrays to be passed. Most of these will correspond
to functions long supported by spreadsheets in general and by Microsoft Excel in
particular. We’ll support functions like MATCH and INDEX, but also functions
like AVERAGEIF, AVERAGEIFS, COUNTIF, COUNTIFS, SUMIF and SUMIFS as well as lots
of new statistical functions.&lt;/p&gt;

&lt;p&gt;We’re also leaning heavily on the new array functions introduced by modern
versions of Excel (requiring a subscription to Microsoft 365). Those include
functions like FILTER, XMATCH and XLOOKUP. (Yes, a true look-up function is
coming to Calcapp, although you’ll have to make do with writing the values in
the formula itself for the time being.)&lt;/p&gt;

&lt;h2 id=&quot;the-finer-points&quot;&gt;The finer points&lt;/h2&gt;

&lt;p&gt;An extra complication is that we insist on something called &lt;em&gt;static typing&lt;/em&gt;.
What that means is that we can flag formula errors which traditional
spreadsheets simply don’t flag. If you try entering the formula &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(4, &quot;true&quot;,
&quot;false&quot;)&lt;/code&gt; in Excel, “true” will be produced, because 4 is assumed to be
equivalent to TRUE (this process is known as &lt;em&gt;type coercion&lt;/em&gt;). Calcapp will
instead present an error and ask you to enter a logical value, potentially
saving you from having to make sense of confusing output.&lt;/p&gt;

&lt;p&gt;Now, capturing all the nuances of Excel formula functions with static typing is
a large undertaking. For instance, SWITCH expects parameters to be given in
pairs, which is something we haven’t had to handle before.&lt;/p&gt;

&lt;p&gt;Another example is SUMIF, which returns the sum of all values in an array, but
only includes values which satisfy a condition. Said condition can be expressed
as a value which an array value must be equal to, or it can be expressed in the
form of a string like “&amp;lt;4” (an array value must be less than four in order to be
considered). In other words, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF({ 2, 2, 10, 4 }, 2)&lt;/code&gt; returns 4 (only the
first two items are added together, because they need to equal 2), whereas
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF({ 2, 2, 10, 4 }, &quot;&amp;gt;2&quot;)&lt;/code&gt; returns 14 (only the last two items are
considered, because they need to be greater than two).&lt;/p&gt;

&lt;p&gt;With SUMIF, if you provide an array of numbers, we must therefore allow the
condition parameter to be either a number or a text string (enabling more
complex conditions like “&amp;lt;4”). That all adds complexity (requiring us to
implement something known as &lt;em&gt;union types&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Finally, we also want to support &lt;em&gt;formula snippets&lt;/em&gt; (also known as &lt;em&gt;lambdas&lt;/em&gt;) in
place of the condition parameter, enabling full use of Calcapp formulas to
determine whether an array item should be considered. With a formula snippet,
you can write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF({ 2, 2, 10, 4 }, &quot;&amp;gt;2&quot;)&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF({ 2, 2, 10, 4 }, Item &amp;gt;
2)&lt;/code&gt;. Full use of Calcapp formulas as the condition parameter means that
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SUMIF({ 2, 2, 10, 4 }, (Item &amp;gt; 2) &amp;amp;&amp;amp; (Item &amp;lt; 10))&lt;/code&gt; will also work.&lt;/p&gt;

&lt;h2 id=&quot;referencing-fields-and-not-their-values&quot;&gt;Referencing fields and not their values&lt;/h2&gt;

&lt;p&gt;To reference the value of a field, you just write the field name in a formula.
In other words, to add the values of &lt;em&gt;Field1&lt;/em&gt; and &lt;em&gt;Field2&lt;/em&gt; together, you just
write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1 + Field2&lt;/code&gt;. However, to reference whether &lt;em&gt;Field1&lt;/em&gt; is visible, you
need to type the field name, followed by a period, followed by the property name
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Visible&lt;/code&gt;. In other words, to add the values of &lt;em&gt;Field1&lt;/em&gt; and &lt;em&gt;Field2&lt;/em&gt; together,
but only if both fields are visible, you need to write something like
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(Field1.Visible &amp;amp;&amp;amp; Field2.Visible, Field1 + Field2, 0)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We could easily have asked you to reference the value of a field by writing
something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1.Value&lt;/code&gt;, but that would have been a mouthful and would
have made your formulas hard to read. In Calcapp 3 (the current version), we
simply assume that you intend to reference the value property if you don’t
explicitly write a period followed by a property name.&lt;/p&gt;

&lt;p&gt;This becomes more complicated in Calcapp 4, because we now want to enable you to
reference not only the value of a field, but also the field directly. The reason
for this new requirement is that we are introducing new functions and properties
that need to directly reference fields, and not their values. For instance,
RESET will be callable from formulas run in response to, say, a button being
pressed, and will reset the field to its initial value. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RESET(Field1)&lt;/code&gt; will
reset &lt;em&gt;Field1&lt;/em&gt;, and it is important that it is passed the field itself and not
its value. (After all, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RESET(4)&lt;/code&gt; wouldn’t make any sense.)&lt;/p&gt;

&lt;p&gt;We don’t want you to have to type either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1.Value&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1.Reference&lt;/code&gt;
(where the latter would get you a reference to the field itself, which would
then work with formula functions like RESET). We want you to be able to type
just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1&lt;/code&gt; and then have Calcapp figure out what you’re referring to. In
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1 + Field2&lt;/code&gt;, we can be certain that you’re looking to add the values of
the two fields together, and in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RESET(Field1)&lt;/code&gt;, we can be certain that you’re
looking for a reference to the field itself.&lt;/p&gt;

&lt;p&gt;(We’ll actually allow you to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1.Value&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1.Reference&lt;/code&gt; to make
the call yourself, in the off chance that Calcapp 4 can’t figure out what you
mean.)&lt;/p&gt;

&lt;h2 id=&quot;our-near-term-plans&quot;&gt;Our near-term plans&lt;/h2&gt;

&lt;p&gt;Our &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;Calcapp 4 project&lt;/a&gt; encompasses far more than a next-generation
formula language, including binding fields to tabular data and a PDF report
designer. The new formula capabilities can be considered the base on which the
full Calcapp 4 experience will be built.&lt;/p&gt;

&lt;p&gt;In the near term, though, we hope to ship many of the formula improvements while
keeping the experience identical in all other respects. To that end, we will
work to make the new Calcapp Compiler work with the existing Calcapp Creator and
Calcapp Connect, creating a sort-of hybrid between Calcapp 4 (the new Calcapp
Compiler) and Calcapp 3 (with lightly updated versions of Calcapp Creator and
Calcapp Connect).&lt;/p&gt;

&lt;p&gt;Then, we’ll commence work on more fully realizing our Calcapp 4 vision.&lt;/p&gt;

</description>
        <pubDate>Wed, 12 Aug 2020 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/08/12/status.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/08/12/status.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Feature: Auto-height for AMP</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  The auto-height feature enables an app embedded in your web page to adjust its
  height in response to content changes. This feature is now also supported for
  AMP, a technology which makes web pages load faster.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;&lt;a href=&quot;https://amp.dev/&quot;&gt;AMP&lt;/a&gt; is a technology used to create speedy websites, originally introduced
by Google in 2015. AMP sites derive their speed advantage from the simpler HTML
mandated by AMP and from caching.&lt;/p&gt;

&lt;p&gt;AMP pages can embed apps created with Calcapp using the &lt;a href=&quot;https://amp.dev/documentation/components/amp-iframe/&quot;&gt;amp-iframe&lt;/a&gt;
tag. (There are some restrictions, though, including the fact that iframes must
not appear close to the top of the document — refer to the AMP documentation
for more information.)&lt;/p&gt;

&lt;p&gt;However, up until now, AMP pages have not been able to use the &lt;a href=&quot;/blog/2019/07/21/auto-height.html&quot;&gt;auto-height
feature we introduced last year&lt;/a&gt;. Our auto-height feature resizes
the containing iframe so that it matches the height of your app as it changes
size, including when users navigate to a new panel and when users cause fields
to become visible or invisible.&lt;/p&gt;

&lt;p&gt;The issue is that AMP pages cannot include arbitrary scripts, such as our
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calcapp-iframe.js&lt;/code&gt; script, which enables containing iframes to be resized.
Instead, AMP requires that their own “AMP runtime” is the only script running on
AMP pages.&lt;/p&gt;

&lt;p&gt;(This isn’t strictly true — AMP supports running third-party scripts using the
&lt;a href=&quot;https://amp.dev/documentation/guides-and-tutorials/develop/custom-javascript/&quot;&gt;amp-script&lt;/a&gt; tag. This facility appears to be quite limited,
though.)&lt;/p&gt;

&lt;p&gt;Luckily, the AMP runtime supports resizing iframes, but only if the iframe in
question supports AMP explicitly. Calcapp now emits events when the height
changes, both for our own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calcapp-iframe.js&lt;/code&gt; library (used on regular websites)
and — as of today — for AMP.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;calcapp-iframe.js&lt;/code&gt; supports constraining the height by setting minimum and
maximum values. This does not work for AMP. Instead, AMP itself ensures that an
iframe is not sized such that it occupies fewer than 100 vertical pixels.&lt;/p&gt;

&lt;p&gt;By default, iframes created through AMP use a “sandbox,” which restricts what
the iframe can do. As apps created through Calcapp use JavaScript pervasively,
you must set a special attribute allowing for scripts to run.&lt;/p&gt;

&lt;p&gt;Use this AMP HTML markup to embed an app you have created:&lt;/p&gt;

&lt;pre class=&quot;highlight&quot;&gt;
  &amp;lt;amp-iframe width=&quot;320&quot;
              height=&quot;480&quot;
              sandbox=&quot;allow-scripts allow-same-origin&quot;
              layout=&quot;responsive&quot;
              frameborder=&quot;0&quot;
              src=&quot;https://connect.calcapp.net/?app=abc123&quot;&amp;gt;
  &amp;lt;/amp-iframe&amp;gt;
&lt;/pre&gt;

</description>
        <pubDate>Mon, 11 May 2020 00:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/05/11/auto-height-amp.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/05/11/auto-height-amp.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
      <item>
        <title>Calcapp 4 is coming</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Calcapp 4 will feature much-improved support for tabular data. Buttons will be
  able to initiate complex workflows and our formula language will gain many new
  features. We hope to deliver the first new features in a few months.
&lt;/div&gt;

&lt;p&gt;Over the past four years, we have &lt;a href=&quot;/blog/tag/feature.html&quot;&gt;incrementally improved Calcapp&lt;/a&gt;.
&lt;a href=&quot;/blog/2019/07/21/embed-tab.html&quot;&gt;Small&lt;/a&gt; and &lt;a href=&quot;/blog/2016/12/21/cross-references.html&quot;&gt;large&lt;/a&gt; features have been added,
&lt;a href=&quot;/blog/2020/01/15/blurry-images.html&quot;&gt;bugs have been squashed&lt;/a&gt; and the &lt;a href=&quot;/blog/2019/04/12/stability.html&quot;&gt;performance has been markedly
improved&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We think that the time for incremental change is over. It’s time for revolution.&lt;/p&gt;

&lt;p&gt;This isn’t the &lt;a href=&quot;/blog/2018/04/09/launching-after-15-years.html&quot;&gt;first time we’ve been down this road&lt;/a&gt;
— the service you use today is internally called Calcapp 3. Calcapp 1 was
created back in 2003 as an easy means of building single-screen calculator
applications for Windows using a text file containing formulas. In 2008, mobile
was booming and we created Calcapp 2, which was capable of building multi-screen
apps for Windows and Android. Calcapp 3, begun in 2014, brought Calcapp into the
web era with an app builder available to anyone, producing slick web apps for
iPhone, iPad, Android and desktop computers.&lt;/p&gt;

&lt;p&gt;It’s 2020, and the time has come to build Calcapp 4. Chiefly, we aim to provide
far better support for &lt;strong&gt;tabular data&lt;/strong&gt; and &lt;strong&gt;formula-driven automation&lt;/strong&gt;, which
we discuss at greater length below.&lt;/p&gt;

&lt;p&gt;You don’t need to worry about your investment in Calcapp, though — all your
existing apps will continue to work and the user experience will still feel
familiar.&lt;/p&gt;

&lt;p&gt;Also, change won’t happen overnight. The new features will be rolled out
incrementally, without affecting stability or performance negatively.&lt;/p&gt;

&lt;h2 id=&quot;tabular-data&quot;&gt;Tabular data&lt;/h2&gt;

&lt;p&gt;The primary innovation Calcapp 4 will bring is much better support for tabular
data. While we support &lt;a href=&quot;/blog/2018/04/06/tabular-data-drop-downs.html&quot;&gt;importing tabular data&lt;/a&gt; for use
with drop-downs and &lt;a href=&quot;/blog/2016/10/18/reporting-email.html&quot;&gt;exporting data to CSV files&lt;/a&gt; or even
&lt;a href=&quot;/blog/2018/05/18/zapier-video.html&quot;&gt;spreadsheets and databases&lt;/a&gt; (through a third-party service), this
is a far cry from being able to write apps that can read the data they
themselves have written.&lt;/p&gt;

&lt;p&gt;Calcapp has excellent support for calculations today. However, calculations
often need to be based on not just raw formulas, but on data, which we don’t
handle well today.&lt;/p&gt;

&lt;p&gt;Also, we think there is a far larger market for apps that can read and write
data than there is for pure calculator apps. We’d like to not only serve our
existing user base better, but also break into this much larger market.&lt;/p&gt;

&lt;p&gt;No-code app builders are exploding in popularity, and what the vast majority of
these app builders have in common is that they have robust support for handling
data — and poor support for calculations and for using formulas for modeling
dynamic behavior in apps. We think that combining Calcapp’s formula prowess with
first-class support for data will produce a truly stellar product.&lt;/p&gt;

&lt;p&gt;Generally, these data-savvy app builders fall into one of two categories. Either
they offer great ease-of-use, but little power (like the slick &lt;a href=&quot;https://www.glideapps.com&quot;&gt;Glide&lt;/a&gt;)
or they offer lots of flexibility, but at the expense of a steep learning curve
and requiring users to learn lots of new concepts (like the well-engineered
&lt;a href=&quot;https://powerapps.microsoft.com&quot;&gt;Microsoft PowerApps&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We think there is room for an app builder that is both easy to get started with
and offers a lot of power through formulas. Further, we think it’s crucial that
this product respects the investment users have made in spreadsheets in general
and in Microsoft Excel in particular, by offering a similar mental model.&lt;/p&gt;

&lt;p&gt;(Others have tried to go down that road in the past, by creating app builders
fully integrated with the Microsoft Excel desktop application. We think that’s a
mistake, as Excel was never meant to be an app builder. For starters, designing
the user interface of an app using Excel’s grid will never yield high-quality
user experiences. We think that any product integrating that deeply with Excel
is needlessly limiting itself.)&lt;/p&gt;

&lt;p&gt;No product on the market meets these criteria today. Our aim is to create it in
the form of Calcapp 4.&lt;/p&gt;

&lt;h2 id=&quot;formula-driven-automation&quot;&gt;Formula-driven automation&lt;/h2&gt;

&lt;p&gt;Apps often need to take complex actions, based on evaluating information entered
in an app. For instance, a button, when pressed, should perhaps send an order to
a warehouse, make a note of the order in a database and then send a confirmation
email to a user. If any of the entered data is not valid, a warning popup may
need to be displayed.&lt;/p&gt;

&lt;p&gt;Calcapp makes no attempt to realize such workflows today. Buttons can only send
or open reports, reset fields or send off data to third-party services. We
recognize that this is limiting.&lt;/p&gt;

&lt;p&gt;We aim to realize automation through formulas, triggered by events such as a
button being pressed. These formulas will be different from regular formulas, in
that they will be able to not just calculate values, but take actions through
special formula functions.&lt;/p&gt;

&lt;p&gt;The current crop of enterprise app builders usually realize automation by
enabling workflows to be described graphically. Users essentially have access to
a palette of actions, where individual actions can be dragged onto a canvas,
allowing multiple steps to be described. There is often special support for
describing conditions, enabling different actions to be taken based on whether a
formula evaluates to TRUE or FALSE.&lt;/p&gt;

&lt;p&gt;Our initial plan calls for using plain Calcapp formulas to realize automation.
There is no reason we couldn’t allow these formulas to be represented
graphically in the future, enabling users a choice between typing formulas and
the graphical approach favored by other app builders. The graphical approach has
the advantage of clearly communicating what actions are available and allowing
their behavior to be easily customized, without requiring users to remember or
look up function names or the order of parameters.&lt;/p&gt;

&lt;h2 id=&quot;formula-improvements&quot;&gt;Formula improvements&lt;/h2&gt;

&lt;p&gt;To support the features listed above, we’ve been hard at work since late last
year adding features to Calcapp formulas.&lt;/p&gt;

&lt;p&gt;Here’s a small sample of the work we have completed so far:&lt;/p&gt;

&lt;h3 id=&quot;if-without-all-the-parentheses&quot;&gt;IF without all the parentheses&lt;/h3&gt;

&lt;p&gt;Expressing multiple conditions with the IF formula function leads to verbose,
hard-to-read formulas, as multiple IF functions need to be nested. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(X = 1,
10, IF(X = 2, 20, IF(X = 3, 30)))&lt;/code&gt; isn’t particularly easy to read, especially
if you need a large number of conditions and values.&lt;/p&gt;

&lt;p&gt;We’ll fix this problem by allowing the extra conditions and values to be
expressed as parameters to the first IF invocation: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(X = 1, 10, X = 2, 20, X
= 3, 30)&lt;/code&gt;. Much better!&lt;/p&gt;

&lt;p&gt;(We’ll also support the new Excel formula function IFS, which does much the same
thing.)&lt;/p&gt;

&lt;h3 id=&quot;support-for-the-switch-formula-function&quot;&gt;Support for the SWITCH formula function&lt;/h3&gt;

&lt;p&gt;Excel recently gained support for the SWITCH formula function, which Calcapp 4
will also support. Think of SWITCH as a simplified version of IF, provided that
you only need to test a single value and you only need to test equality.&lt;/p&gt;

&lt;p&gt;The first parameter to SWITCH is the value to test. If this value is equal to
the second parameter, the third parameter is returned. Otherwise, SWITCH
compares the first parameter to the fourth parameter, and if those values are
equal to one another, the fifth parameter is returned, and so on.&lt;/p&gt;

&lt;p&gt;Here’s the IF formula above, rewritten to use SWITCH:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SWITCH(X, 1, 10, 2, 20, 3, 30)&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;more-types&quot;&gt;More types&lt;/h3&gt;

&lt;p&gt;Every value reachable through a Calcapp formula has traditionally been a number,
a logical value or a text string (known as the &lt;em&gt;type&lt;/em&gt; of the value). That is
unfortunately quite limiting.&lt;/p&gt;

&lt;p&gt;We have received many requests for enabling buttons to navigate to various parts
of an app, using a formula to determine the target panel. As formulas haven’t
been able to reference panels, we haven’t been able to implement that feature.&lt;/p&gt;

&lt;p&gt;Also, countless customers have asked us to make which fields are included in
reports customizable through formulas. As referencing fields through formulas
hasn’t been possible, we’ve had to postpone adding that feature.&lt;/p&gt;

&lt;p&gt;Calcapp 4 changes all that, by adding lots of new types, including the
aforementioned panels and fields. We look forward to adding new properties and
formula functions taking advantage of the new types.&lt;/p&gt;

&lt;h3 id=&quot;action-formulas&quot;&gt;Action formulas&lt;/h3&gt;

&lt;p&gt;We refer to formulas which can execute actions as &lt;em&gt;action formulas&lt;/em&gt;. These
formulas will have access to special formula functions, known as &lt;em&gt;action
functions&lt;/em&gt;, which can execute actions.&lt;/p&gt;

&lt;p&gt;Action formulas will also be special in that they will be able to execute
multiple actions and thus invoke multiple action functions. You will probably
write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; between such invocations.&lt;/p&gt;

&lt;p&gt;Here’s an example which sends a report and displays a message if and only if the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Result&lt;/code&gt; field is valid, and otherwise displays an error message:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IF(Result.Valid, SENDREPORT(...); ALERT(&quot;Done!&quot;), ALERT(&quot;Invalid result!&quot;))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, action formulas will be able to set values, probably by writing
something akin to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Field1 := Field2 * 2&lt;/code&gt;. Note the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; symbol — that’s an
&lt;em&gt;assignment operator&lt;/em&gt;, which assigns the value on the right-hand side to the
property on the left-hand side. This will enable buttons to do things like
incrementing values, without having to use a stepper, or perform calculations.&lt;/p&gt;

&lt;p&gt;(VBA users are used to using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt; both for assignment and equality. We think
that’s confusing, so we’ll probably use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:=&lt;/code&gt; for assignment instead.)&lt;/p&gt;

&lt;h3 id=&quot;formula-snippets&quot;&gt;Formula snippets&lt;/h3&gt;

&lt;p&gt;Some action functions will ask that you supply formula snippets that are
executed at a later point in time, snippets which may have access to additional
values. (In programming lingo, these snippets are known as &lt;em&gt;lambdas&lt;/em&gt;, or
&lt;em&gt;anonymous functions&lt;/em&gt;.)&lt;/p&gt;

&lt;p&gt;For instance, an action function asking the user to enter a value in a
popup may make the response available as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Response&lt;/code&gt; value:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QUERY(&quot;What is your name?&quot;, ALERT(&quot;Your name is &quot; &amp;amp; Response &amp;amp; &quot;!&quot;))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Above, the (fictitious) QUERY formula function takes two parameters: the
question to pose to the user and a formula snippet which is provided the
response and is executed when the user presses a button.&lt;/p&gt;

&lt;p&gt;Naming the values which are provided to these formula snippets may result in
easier-to-read formulas. Naming values will be supported using optional
so-called &lt;em&gt;arrows&lt;/em&gt; (note the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&amp;gt;&lt;/code&gt; symbol):
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;QUERY(&quot;What is your name?&quot;, Name -&amp;gt; ALERT(&quot;Your name is &quot; &amp;amp; Name &amp;amp; &quot;!&quot;))&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&quot;other-changes&quot;&gt;Other changes&lt;/h2&gt;

&lt;p&gt;We have promised a PDF report designer for the longest time now. We aim to
deliver one, but we will deliver better support for tabular data and
formula-driven automation first.&lt;/p&gt;

&lt;p&gt;We are also aware that many customers want to create apps and upload them to app
stores. Some enterprising Calcapp customers have found ways to do so using
third-party software, and we expect this process to become easier now that apps
produced through Calcapp are &lt;a href=&quot;/blog/2020/04/02/offline.html&quot;&gt;true Progressive Web Apps&lt;/a&gt; (PWAs). However,
supporting app store submissions out-of-the-box would be a complex undertaking
and isn’t something we plan to prioritize in the near term.&lt;/p&gt;

&lt;p&gt;Finally, we expect Calcapp 4 to deliver myriad smaller improvements. Calcapp 3
was started in early 2014 and the technology landscape has improved markedly
since then. We aim to adopt new technology to make maintaining Calcapp easier
and to improve performance. We plan to use that opportunity to address
long-standing usability problems, including adding support for undo and redo in
Calcapp Creator and more robust formula editing.&lt;/p&gt;

&lt;p&gt;We hope to deliver the first fruits of our labor in a couple of months. The
first features we plan to deliver are the formula improvements discussed above
and support for formula-driven automation. Then, we look forward to sinking our
teeth into adding support for tabular data.&lt;/p&gt;

</description>
        <pubDate>Thu, 02 Apr 2020 13:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/04/02/calcapp-4.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/04/02/calcapp-4.html</guid>
        
        <category>Uncategorized</category>
        
        
      </item>
    
      <item>
        <title>Release: Our April, 2020 update is here</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Apps now work better offline and, as a result, qualify as Progressive Web Apps
  (PWAs). iPhone users can now easily enter decimal numbers. There are new
  features for managing users of private apps. Finally, we describe our upcoming
  project Calcapp 4, with much-improved support for tabular data.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;h2&gt;What&apos;s new?&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;Improved offline experience, PWA support.&lt;/strong&gt;
    Apps built with Calcapp now qualify as Progressive Web Apps (PWAs), enabling
    more third-party tools to work with them. We have also made our offline
    experience more robust, flexible and performant.
    &lt;a href=&quot;/blog/2020/04/02/offline.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Easily enter decimal numbers on an iPhone.&lt;/strong&gt;
    Apps run on iPhones now use a keypad with a decimal separator button, making
    it easy to enter decimal numbers.
    &lt;a href=&quot;/blog/2020/04/02/iphone-keypad.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Add users in bulk, download users as CSV.&lt;/strong&gt;
    Users who are permitted to access your private apps can now be added in
    bulk. Also, you can now download the entire list of users, complete with
    tags, as a CSV file, which can easily be imported into a spreadsheet.
    &lt;a href=&quot;/blog/2019/09/10/csv-users.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Improved email deliverability.&lt;/strong&gt;
    We have significantly improved deliverability of email sent from
    calcapp.net, including reports sent from your apps. We now recommend that
    you use the Reply-To field, instead of the Sender field, to direct replies
    to your reports.
    &lt;a href=&quot;/blog/2019/10/24/deliverability.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Download app statistics as a CSV file.&lt;/strong&gt;
    You can now download statistics for your app as a CSV file, which you can
    easily import into your spreadsheet. Use your spreadsheet&apos;s formulas to
    process the data and visualize it through graphs. For private apps, the CSV
    file has information on how individual users are using your app.
    &lt;a href=&quot;/blog/2019/08/22/csv-statistics.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;Usage statistics on individual users.&lt;/strong&gt;
    The Statistics window now enables you to learn how a particular user is
    using a private app. For such apps, there is a new drop-down menu with a
    list of all users you have defined in the Statistics window.
    &lt;a href=&quot;/blog/2019/08/06/user-statistics.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;

  &lt;li&gt;
    &lt;strong&gt;No more blurry images.&lt;/strong&gt;
    When you upload an image, we resize it to a number of lower resolutions so
    that low-resolution devices don&apos;t have to download more than they need.
    However, we failed to make the original version available, which could lead
    to blurry images. This issue has been fixed.
    &lt;a href=&quot;/blog/2020/01/15/blurry-images.html&quot;&gt;
      Learn&amp;nbsp;more&amp;nbsp;»
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Calcapp 4 is coming&lt;/h2&gt;
&lt;p&gt;
  Calcapp 4 will feature much-improved support for tabular data. Buttons will be
  able to initiate complex workflows and our formula language will gain many new
  features. We hope to deliver the first new features in a few months.
  &lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;
    Learn&amp;nbsp;more&amp;nbsp;»
  &lt;/a&gt;
&lt;/p&gt;
</description>
        <pubDate>Thu, 02 Apr 2020 12:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/04/02/release.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/04/02/release.html</guid>
        
        <category>Release</category>
        
        
      </item>
    
      <item>
        <title>Feature: Improved offline experience, PWA support</title>
        <description>&lt;div class=&quot;excerpt&quot;&gt;
  Apps built with Calcapp now qualify as Progressive Web Apps (PWAs), enabling
  more third-party tools to work with them. We have also made our offline
  experience more robust, flexible and performant.
&lt;/div&gt;

&lt;!-- excerpt end --&gt;

&lt;p&gt;Apps created with Calcapp have been able to &lt;a href=&quot;/blog/2016/08/02/offline.html&quot;&gt;run offline for years
now&lt;/a&gt; (provided that you opt for a Business plan or better). Thanks
to offline support, an app remains accessible even if a user is on a plane or in
a rural area with spotty coverage.&lt;/p&gt;

&lt;p&gt;When we built Calcapp’s offline feature in 2016, we used a technology known as
appcache. A successor technology, named &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&quot;&gt;service workers&lt;/a&gt;, was
supported by Google on the Android version of Chrome, but Apple’s Safari did not
have support. As such, we chose AppCache because it was supported on both
Android and on iOS.&lt;/p&gt;

&lt;p&gt;Starting in April, Google Chrome will drop support for AppCache, and other
browser vendors will likely follow suit. Had we done nothing, apps built with
Calcapp would stop working offline in less than a month on Android.&lt;/p&gt;

&lt;p&gt;Luckily, we have monitored the situation carefully over the last couple of
years, and we were prepared for this development. Calcapp has now been moved
fully to service workers, meaning that your apps will continue to work offline.&lt;/p&gt;

&lt;h2 id=&quot;progressive-web-apps&quot;&gt;Progressive Web Apps&lt;/h2&gt;

&lt;p&gt;Supporting service workers means that your apps now qualify as so-called
Progressive Web Apps (PWAs). A PWA can run as a website inside your browser, but
can also feature capabilities more in line with what a native app offers. They
can be installed on your desktop computer, or they can be added to your Android
or iOS home screen. They run offline. There are also provisions for
synchronizing and downloading data in the background and for sending push
notifications, though Calcapp does not take advantage of those provisions as of
today.&lt;/p&gt;

&lt;p&gt;Calcapp makers have asked for PWA support for years now. The primary reason is
that there are various third-party tools that are able to work with PWAs and not
plain websites. For instance, Microsoft allows PWAs to be &lt;a href=&quot;https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-edgehtml/microsoft-store&quot;&gt;submitted directly to
the Microsoft Store&lt;/a&gt;. Also, Google now offers some support
for &lt;a href=&quot;https://css-tricks.com/how-to-get-a-progressive-web-app-into-the-google-play-store/&quot;&gt;submitting PWAs to Google Play&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;(There are smaller improvements as well. Adding a plain website to your home
screen on Android &lt;a href=&quot;/blog/2018/12/08/pwa.html&quot;&gt;adds a small Chrome overlay icon&lt;/a&gt;. PWAs added
to your home screen get no overlay icon, which arguably looks more
professional.)&lt;/p&gt;

&lt;p&gt;Getting an app built with Calcapp into an app store still requires quite a bit
of work on your part. We’d like to streamline the process, but we currently have
&lt;a href=&quot;/blog/2020/04/02/calcapp-4.html&quot;&gt;a lot of other work&lt;/a&gt; that takes priority.&lt;/p&gt;

&lt;h2 id=&quot;offline-improvements&quot;&gt;Offline improvements&lt;/h2&gt;

&lt;p&gt;Now that we have redone Calcapp’s offline support, we have taken the opportunity
to subtly improve the offline experience. Here’s a list of the improvements you
can expect:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Improved performance.&lt;/strong&gt; Apps are made available for offline use faster when
you first load them. On Android, we have managed to shave a few seconds off
the time it takes for the “This app is now ready to be used offline” message
to appear. On iOS, the message is now shown as quickly as on Android, which is
a dramatic improvement. (Before, users would sometimes need to wait a full
minute before the message appeared.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;A more robust experience.&lt;/strong&gt; Customers sometimes encountered issues with the
older offline experience based on AppCache, &lt;a href=&quot;/blog/2017/11/22/reload-loop.html&quot;&gt;most often on iOS&lt;/a&gt;.
Sometimes, the only recourse was to remove a problematic app from the home
screen and re-install it. We have a lot more control over the new offline
experience, meaning that we think it will prove more robust.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Images and fonts are downloaded in the background.&lt;/strong&gt; When an app is stored
for offline use, images and fonts are stored too. Before, we had to download
and store everything before the loading screen of your app would show, which
led to a bad experience primarily for apps using lots of images. Thanks to the
flexibility of service workers, we now start your app immediately once all the
core resources have been loaded and then download fonts and images in the
background, leading to a faster experience.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Embedded apps never ask users to update them.&lt;/strong&gt; When an app is run for the
first time, it’s downloaded and stored locally on the device itself. The next
time it’s started, that local data is consulted to ensure that the app starts
as quickly as a native app. If the user is online, Calcapp checks if there is
a newer version available. If there is, the user may be asked to reload the
app so that the newest version is run. However, this is not desirable for apps
embedded in other websites. Luckily, service workers give us the flexibility
to disable the offline experience when apps are embedded, so starting today,
users of embedded apps will never be asked to reload an app.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Deferring an app update.&lt;/strong&gt; As noted above, users are sometimes asked to
reload an app when it has been updated. While this message is typically
presented only a few seconds after an app has been loaded, it can still be
inconvenient to have to reload an app, especially in the rare case that the
user has started entering data into the app. For this reason, users can now
press the &lt;strong&gt;Later&lt;/strong&gt; button to continue working in the app without reloading
it. (The next time the user starts the app, the latest version will be run.)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Thu, 02 Apr 2020 11:00:00 +0000</pubDate>
        <link>https://www.calcapp.net/blog/2020/04/02/offline.html</link>
        <guid isPermaLink="true">https://www.calcapp.net/blog/2020/04/02/offline.html</guid>
        
        <category>Feature</category>
        
        
      </item>
    
  </channel>
</rss>
