I have a form that has a question asking about the total number of upper floors and lower floors in a building. So If a building has 4 floors and 2 underground floors then the enumerator should enter 4 in the upper floor question and 2 in the lower floor question.
Then the enumerator should list the units/households in each floor. So for each unit, I created a repeat. Inside each repeat, the enumerator should put the floor number of the unit that he is interviewing. So for unit number 1, the floor could be 1, the unit number 5, the floor could be 2 etc.. However, it is possible that the unit exist in a floor that is underground, so for unit number 6, the floor is -1.
I want to put a constraint that compares the sum of the upper and lower floors (4+2 = 6 in the above example) and the sum of the max of the floors that the enumerator entered in the repeat. So in the above example, if the enumerator entered the info for units in floor 2 and floor -1, then we should add 2 + 1 = 3 and compare 3 to 6. Since they are different then a message should appear that the enumerator didn't visit all the floors.
How can I do that?
Thanks
Edit: I added a screenshot of the form
Solved! Go to Solution.
Hi
I accepted your challenge (in part) and came up with one possible solution:
Hopefully your survey is not a public survey, then you can use JavaScript to achieve your requirement:
I'm not sure if you will have a floor zero but in any case, your solution could be similar.
Basically I made a list of all the floors visited and passed it to a JavaScript function to remove duplicates, sort the floors entered, and comma separate the list:
pulldata("@javascript", "functions.js", "CapturedFloors", ${floor_number})
Where floor_number is the floor entered into your repeat...
function CapturedFloors (floors)
{
var uniq_floors = [...new Set(floors)];
var sort_floors = uniq_floors.sort();
return sort_floors.join(",");
}
Next I used the floor numbers indicated to create a similar comma separated floor list:
pulldata("@javascript", "functions.js", "FloorList", ${floor_lower}, ${floor_upper})
function CapturedFloors (floors)
{
var uniq_floors = [...new Set(floors)];
var sort_floors = uniq_floors.sort();
return sort_floors.join(",");
}
I would then compare the two lists with each other and they should be similar when a fieldworker has visited all the floors of the building:
I hope this helps!
function MissingFloorList(lower,upper,floors)
{
let arr = [];
for (let i = lower; i <= upper; i++) {
arr.push(i);
}
var all_uniq_floors = [...new Set(arr)];
var visited_floors = [...new Set(floors)];
return all_uniq_floors.filter(x => visited_floors.indexOf(x) === -1);
}
Now you can just call one function to retrieve the missing floors and show them in red:
pulldata("@javascript", "functions.js", "MissingFloorList", ${floor_lower}, ${floor_upper},${floor_number})
Show it in a note field with HTML formatting:
<div style="text-align:center; font-size:large; font-weight: bold; color:red"; >Missing floors: ${missingfloors}</div>
Hi
I accepted your challenge (in part) and came up with one possible solution:
Hopefully your survey is not a public survey, then you can use JavaScript to achieve your requirement:
I'm not sure if you will have a floor zero but in any case, your solution could be similar.
Basically I made a list of all the floors visited and passed it to a JavaScript function to remove duplicates, sort the floors entered, and comma separate the list:
pulldata("@javascript", "functions.js", "CapturedFloors", ${floor_number})
Where floor_number is the floor entered into your repeat...
function CapturedFloors (floors)
{
var uniq_floors = [...new Set(floors)];
var sort_floors = uniq_floors.sort();
return sort_floors.join(",");
}
Next I used the floor numbers indicated to create a similar comma separated floor list:
pulldata("@javascript", "functions.js", "FloorList", ${floor_lower}, ${floor_upper})
function CapturedFloors (floors)
{
var uniq_floors = [...new Set(floors)];
var sort_floors = uniq_floors.sort();
return sort_floors.join(",");
}
I would then compare the two lists with each other and they should be similar when a fieldworker has visited all the floors of the building:
I hope this helps!
Great Solution.. Thanks for that.
I think the second function should named FloorList (floors) and its definition should be different.
I guess something like the below
function FloorList(lower,upper)
{
let arr = [];
for (let i = lower; i <= upper; i++) {
arr.push(i);
}
var uniq_floors = [...new Set(arr)];
return uniq_floors.join(",");
}
Btw, Is there a way to highlight or put in a note just the missing floors?
EDIT: I enhance your code
/*
* JavaScript functions for Survey123
*/function CapturedFloors (floors)
{
var uniq_floors = [...new Set(floors)];
var sort_floors = uniq_floors.sort();
return sort_floors.join(",");
}
function FloorList(lower,upper)
{
let arr = [];
for (let i = lower; i <= upper; i++) {
arr.push(i);
}
var uniq_floors = [...new Set(arr)];return uniq_floors.join(",");
}function GetMissingFloors (visitedFloors,lower, upper)
{
let arr = [];
if(!Array.isArray(visitedFloors)){
return; }
for (let i = lower; i <= upper; i++) {
arr.push(i);
}let completeFloors = [...new Set(arr)];
let missingFloors = completeFloors.filter(e => !visitedFloors.includes(e))
return missingFloors.join(", ");
}
function MissingFloorList(lower,upper,floors)
{
let arr = [];
for (let i = lower; i <= upper; i++) {
arr.push(i);
}
var all_uniq_floors = [...new Set(arr)];
var visited_floors = [...new Set(floors)];
return all_uniq_floors.filter(x => visited_floors.indexOf(x) === -1);
}
Now you can just call one function to retrieve the missing floors and show them in red:
pulldata("@javascript", "functions.js", "MissingFloorList", ${floor_lower}, ${floor_upper},${floor_number})
Show it in a note field with HTML formatting:
<div style="text-align:center; font-size:large; font-weight: bold; color:red"; >Missing floors: ${missingfloors}</div>