I´m an angular newbie
I have a directive with a template that looks something like this:
<div class="multiselect-styled">
<a href="javascript:void(0);" class="link" id="link-{{ model.ControlId }}">
<span class="options-selected" id="selected-options-{{ model.ControlId }}">TEXT</span>
<span class="select-arrows"></span>
</a>
</div>
My model contains an array called Options which contains n number of selectable options. Each option object has a boolean property; Selected. I would like to replace TEXT with a string saying n options selected. So, how do I get the number of selected options?
Of course, using a loop one would do something like this but is there some way I kind bind directly to n in this case (Find n with an expression)?
var n = 0;
angular.forEach(model.Options, function(option) {
if (option.Selected)
n++;
});
UPDATE 1
Options look like this:
"Options": [
{
"Id": "ApprovedAndClosed",
"Value": "ApprovedAndClosed",
"Text": "ApprovedAndClosed",
"Selected": false,
"Code": "ApprovedAndClosed"
},
{
"Id": "Cancel",
"Value": "Cancel",
"Text": "Cancel",
"Selected": false,
"Code": "Cancel"
},
{
"Id": "Done",
"Value": "Done",
"Text": "Done",
"Selected": false,
"Code": "Done"
},
{
"Id": "Init",
"Value": "Init",
"Text": "Init",
"Selected": false,
"Code": "Init"
},
{
"Id": "ReadyForProcessing",
"Value": "ReadyForProcessing",
"Text": "ReadyForProcessing",
"Selected": false,
"Code": "ReadyForProcessing"
},
{
"Id": "Rejected",
"Value": "Rejected",
"Text": "Rejected",
"Selected": false,
"Code": "Rejected"
},
{
"Id": "Reminder",
"Value": "Reminder",
"Text": "Reminder",
"Selected": false,
"Code": "Reminder"
}
]
You can try using a filter:
{{(model.Options | filter:{'Selected': true}).length}}
You could use lodash for this:
var countSelected = _.filter(Options, { 'Selected': true});
console.log(countSelected.length);
See: codepen example
Related
I'm trying to add a custom property that will hold a boolean for check if a response change should display a popup.
This is a part of my survey.json:
{
"type": "radiogroup",
"name": "q1",
"title": {
"default": "Question number one?"
},
"displayAlert": true,
"isRequired": true,
"choices": [
{
"value": "yes",
"text": {
"default": "Yes"
}
},
{
"value": "no",
"text": {
"default": "No"
}
}
]
}
As you can see there is a displayAlert property.
I want to read this property when there is a change in that answer:
this.userSurvey.onValueChanging.add((survey: any, change: any) => {
console.log('alert?', change.question.displayAlert);
});
I've also set this but it don't work:
Serializer.addProperty('itemvalue', {
name: 'displayAlert',
category: 'general',
});
Thanks in advance.
You need to add a property not to itemValue, but to the question type.
Survey.Serializer.addProperty("question",
{
name: 'displayAlert',
category: 'general',
}
)
var json = {
"pages": [
{
"name": "page1",
"elements": [
{
"type": "radiogroup",
"name": "q1",
"title": "Question number one?",
"displayAlert": true,
"isRequired": true,
"choices": [
{
"value": "yes",
"text": {
"default": "Yes"
}
},
{
"value": "no",
"text": {
"default": "No"
}
}
]
}
]
}]
};
...
survey.onValueChanging.add(function(survey, change) {
console.log('alert?', change.question.displayAlert);
});
Try this example: https://plnkr.co/edit/ggW5NkqCWdoSHfZ6.
I have an object parsed from JSON output.
I have to use only pure JS without any 3rd part libs. Can somebody suggest a working solution to filter a specific nested object by one of its key's value. In this sample I have a few "Fields" objects which contains also nested objects.
So is there a way to filter the whole nested object inside Fields using VName value as a filter criteria? For example use "VName": "oc_data" to filter the whole object inside Fields oc_data belongs to
[{
"Id": "0050560107dd",
"Name": "Demo Range",
"AllMup": false,
"Lines": [{
"Id": "0050560107dd",
"AllMup": false,
"Fields": [{
"Id": "0050560107dd",
"Name": "Some value here",
"VName": "oc_data",
"IsRequired": false,
"Format": {
"Type": "Dictionary",
"Dictionary": {
"Name": "Main stuff",
"SysName": "da3a45de77d1",
"ValuesUrl": "https://mysityurl.com",
"Id": "0050560107dd",
},
"CalForm": []
}
}]
},
{
"Id": "0050560107dd",
"AllMup": false,
"Fields": [{
"Id": "0050560107dd",
"Name": "Some value again",
"VName": "task_stat",
"IsRequired": false,
"Format": {
"Type": "Dictionary",
"Dictionary": {
"Name": "Task stuff",
"SysName": "Tasks.TaskState",
"ValuesUrl": "https://mysecondurl.com",
"Id": "ac1f6b17f99d",
},
"CalForm": []
}
}]
}
]
},
{
"Id": "0050560107dd",
"Name": "Demo Range",
"AllMup": false,
"Lines": [{
"Id": "0050560107dd",
"AllMup": false,
"Fields": [{
"Id": "0050560107dd",
"Name": "Category",
"IsRequired": false,
"Format": {
"Type": "Dictionary",
"Dictionary": {
"Name": "Some category",
"SysName": "LitigationCategory",
"ValuesUrl": "https://myempty.com",
"Id": "902b343a9588",
},
"CalForm": []
}
}]
}]
}
]
I have an array of objects that looks something like this:
const roles = [
{
"id": "833ffe3d-cc24-4157-966c-5f8ceb856f4e",
"hidden": false,
"modified": "2020-03-20T15:14:12.689Z",
"label": "Solution 2",
"shortname": "Solution 2",
"description": "Solution 2 description",
"className": "Solution",
"children": [
{
"id": "f1708329-eb9f-4042-bbe7-cdd1ff41b1b7",
"hidden": false,
"modified": "2020-03-20T15:14:12.293Z",
"label": "USER CUSTOM ROLE",
"displayName": "USER CUSTOM ROLE DISPLAY NAME",
"className": "Role"
}
]
},
{
"id": "1a36709f-4de2-4f93-bf8e-57811d36e9f3",
"hidden": false,
"modified": "2020-03-20T15:14:12.668Z",
"label": "Solution 1",
"shortname": "Solution 1",
"description": "Solution 1 description",
"className": "Solution",
"children": [
{
"id": "e824afbd-8b19-4363-b6fa-dd604f445cef",
"hidden": false,
"modified": "2020-03-20T15:14:12.271Z",
"label": "USER ROLE",
"displayName": "USER ROLE DISPLAY NAME",
"className": "Role"
},
{
"id": "8f2600d0-5328-4d41-8270-2eb10541860f",
"hidden": false,
"modified": "2020-03-20T15:14:12.095Z",
"label": "BASE LOGIN ROLE",
"displayName": "DISPLAY NAME - BASE LOGIN ROLE",
"className": "Role"
},
{
"id": "a14ce471-b792-4a5d-95ad-b9abb5dbe45c",
"hidden": false,
"modified": "2020-03-20T15:14:12.102Z",
"label": "ORGANIZATION GLOBAL ROLE",
"displayName": "DISPLAY NAME - GLOBAL ROLE",
"className": "Role"
},
{
"id": "d4a7d6ac-1663-48be-9fed-ce2a908f28f1",
"hidden": false,
"modified": "2020-03-20T15:14:12.130Z",
"label": "DEPARTMENT 1 ROLE",
"className": "Role"
}
]
}
];
Point of my concern is id, label and children of these objects. As you can see, some of the roles objects contain their own roles array. And I have another array of selected roles, which looks like this:
const selected = ["Solution 1", "USER ROLE", "DEPARTMENT 1 ROLE"];
What I want is to create flat array of IDs corresponding to the selected roles, e.g. for this
selected array it will be (order is not important):
const result = ["d4a7d6ac-1663-48be-9fed-ce2a908f28f1", "e824afbd-8b19-4363-b6fa-dd604f445cef", "1a36709f-4de2-4f93-bf8e-57811d36e9f3"];
So my algorithm in pseudocode is:
1. Check root level object.
2. If it's label is in selected array, push it's id to the result array.
3. If it has children prop, check all it's children for the same condition.
4. Repeat for all other objects.
I've been only able to come up with very smelly function on this own and it still doesn't solve problem of the nested roles. My function is:
function getIds(arr, names) {
let result = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < names.length; j++) {
if (arr[i].label == names[j]) {
result.push(arr[i].id);
}
if (arr[i].children) {
for (let k = 0; k < arr[i].children.length; k++) {
if (arr[i].children[k].label == names[j]) {
result.push(arr[i].children[k].id);
}
}
}
}
}
return result;
}
I know, there are much more cleaner and prettier solutions, I just can't come up with one. Can you help?
First I would flatten the array what you have with roles using .flatMap(). Then simply with .map() matching the labels with the array elements and returning the ids.
Try the following:
const selected = ["Solution 1", "USER ROLE", "DEPARTMENT 1 ROLE"];
const roles = [{ "id": "833ffe3d-cc24-4157-966c-5f8ceb856f4e", "hidden": false, "modified": "2020-03-20T15:14:12.689Z", "label": "Solution 2", "shortname": "Solution 2", "description": "Solution 2 description", "className": "Solution", "children": [{ "id": "f1708329-eb9f-4042-bbe7-cdd1ff41b1b7", "hidden": false, "modified": "2020-03-20T15:14:12.293Z", "label": "USER CUSTOM ROLE", "displayName": "USER CUSTOM ROLE DISPLAY NAME", "className": "Role" } ] }, { "id": "1a36709f-4de2-4f93-bf8e-57811d36e9f3", "hidden": false, "modified": "2020-03-20T15:14:12.668Z", "label": "Solution 1", "shortname": "Solution 1", "description": "Solution 1 description", "className": "Solution", "children": [{ "id": "e824afbd-8b19-4363-b6fa-dd604f445cef", "hidden": false, "modified": "2020-03-20T15:14:12.271Z", "label": "USER ROLE", "displayName": "USER ROLE DISPLAY NAME", "className": "Role" }, { "id": "8f2600d0-5328-4d41-8270-2eb10541860f", "hidden": false, "modified": "2020-03-20T15:14:12.095Z", "label": "BASE LOGIN ROLE", "displayName": "DISPLAY NAME - BASE LOGIN ROLE", "className": "Role" }, { "id": "a14ce471-b792-4a5d-95ad-b9abb5dbe45c", "hidden": false, "modified": "2020-03-20T15:14:12.102Z", "label": "ORGANIZATION GLOBAL ROLE", "displayName": "DISPLAY NAME - GLOBAL ROLE", "className": "Role" }, { "id": "d4a7d6ac-1663-48be-9fed-ce2a908f28f1", "hidden": false, "modified": "2020-03-20T15:14:12.130Z", "label": "DEPARTMENT 1 ROLE", "className": "Role" } ] } ];
const flat = roles.flatMap(e => e.children.concat(e));
const result = selected.map(e => flat.find(f => f.label === e).id);
console.log(selected);
console.log(result);
I hope this helps!
I have Analysis Paralysis and need some input. I can modify the SQL query, the JavaScript, AND/or the CFML controller (all code has been posted below).
All I'm looking to do is to populate a select box with options and optgroups. The optgroup is what is tripping me up here.
The sql is pretty basic and looks like this:
SELECT
g.groupID,
g.groupLabel,
u.unitLabel,
u.unitID
FROM
group g
LEFT JOIN unit u ON g.groupID = u.groupID
And the CFML loop(s) is as follows (this is also where I believe the adjustment should be made with some logic such as if thisGroupLabel matches the preGroupLabel, stay within loop and keep adding unitLabel and unitIDs) but is there a more efficient way?:
local.data.unitLabels = [];
for(local.row in local.__unitLabels){
local.unit = {};
local.unit.groupLabel = local.row.groupLabel;
local.unit.unitLabel = local.row.unitLabel;
local.unit.unitID = local.row.unitID;
// loop over the array so that we can identify which one needs to be preselected
for(local.dataValue in local.data.unitDetails){
if (local.unit.unitID eq local.dataValue.unitID) {
local.unit.selected = 'selected';
} else {
local.unit.selected = '';
}
}
arrayAppend(local.data.unitLabels, local.unit);
}
The JSON data looks like this but I have access to the query so I can reformat it if needed:
{
"data": {
"selectDataOptions": [{
"groupLabel": "COMPLETION",
"selected": "",
"unitID": 1,
"unitLabel": "Completion"
}, {
"groupLabel": "DISTANCE",
"selected": "",
"unitID": 2,
"unitLabel": "Meters"
}, {
"groupLabel": "DISTANCE",
"selected": "",
"unitID": 3,
"unitLabel": "Miles"
}, {
"groupLabel": "DISTANCE",
"selected": "",
"unitID": 4,
"unitLabel": "Yards"
}, {
"groupLabel": "TIME",
"selected": "",
"unitID": 5,
"unitLabel": "Hours"
}, {
"groupLabel": "TIME",
"selected": "",
"unitID": 5,
"unitLabel": "minutes"
}, {
"groupLabel": "TIME",
"selected": "",
"unitID": 5,
"unitLabel": "Seconds"
}]
}
}
As it stands, my select box looks like this (roughly):
<select>
<optgroup>COMPLETION</optgroup>
<option>Complettion</option>
<optgroup>DISTANCE</OPTGROUP>
<option>Meters</option>
<optgroup>DISTANCE</optgroup>
<option>Miles</option>
<optgtroup>DISTANCE</optgroup>
<option>Yards</option>
<optgtroup>TIME</optgroup>
<option>Hours</option>
<optgtroup>TIME</optgroup>
<option>Minutes</option>
</select>
Notice that the optgroup Distance and TIME are repeated. The desired output would look like this:
<select>
<optgroup>COMPLETION</optgroup>
<option>Complettion</option>
<optgroup>DISTANCE</OPTGROUP>
<option>Meters</option>
<option>Miles</option>
<option>Yards</option>
<optgroup>TIME</optgroup>
<option>Hours</option>
<option>Mintues</option>
</select>
Is the issue how to construct a JSON string that Select2 can understand? I'd suggest creating a nested array of children for each GroupLabel, as described in the documentation under Grouped Data.
CF11+ and Lucee 4.5+ support cfloop "group", which would make things a lot easier. Just cfloop through the query and group by "groupLabel". (NB: Don't forget to modify the SQL query and ORDER BY g.groupLabel so the grouping works as expected.)
TryCF.com Example
Code:
data= [];
cfloop(query="qDemo", group="groupLabel") {
children = [];
cfloop() {
arrayAppend(children, {"id": qDemo.unitID, "text": qDemo.unitLabel});
}
arrayAppend(data, {"text" : qDemo.GroupLabel, "children" : children });
}
writeDump(serializeJSON(data));
Result:
[
{
"text": "COMPLETION",
"children": [
{
"text": "Completion",
"id": 1
}
]
},
{
"text": "DISTANCE",
"children": [
{
"text": "Meters",
"id": 2
},
{
"text": "Miles",
"id": 3
},
{
"text": "Yards",
"id": 4
}
]
},
{
"text": "TIME",
"children": [
{
"text": "Hours",
"id": 5
},
{
"text": "minutes",
"id": 5
},
{
"text": "Seconds",
"id": 5
}
]
}
]
In my application I have a ajax call and am getting the following response based on this am constructing the questions & answer section which I have included in the JSFiddle
var responseQuestions = {
"error": false,
"message": "Success",
"result": {
"Questions": [{
"Id": "131a",
"Text": "In what county do you live?",
"Answers": [{
"Id": "abc1",
"Text": "option1"
},
{
"Id": "abc2",
"Text": "option2"
},
{
"Id": "abc3",
"Text": "option3"
},
{
"Id": "abc4",
"Text": "option4"
},
{
"Id": "abc5",
"Text": "option5"
}
],
"SelectedAnswerId": null
},
{
"Id": "132a",
"Text": "Which zip code has ever been a part of your address?",
"Answers": [{
"Id": "def1",
"Text": "option1"
},
{
"Id": "def2",
"Text": "option2"
},
{
"Id": "def3",
"Text": "option3"
},
{
"Id": "def4",
"Text": "option4"
},
{
"Id": "def5",
"Text": "option5"
}
],
"SelectedAnswerId": null
},
{
"Id": "133a",
"Text": "What was the original amount of your most recent mortgage?",
"Answers": [{
"Id": "ghi1",
"Text": "option1"
},
{
"Id": "ghi2",
"Text": "option2"
},
{
"Id": "ghi3",
"Text": "option3"
},
{
"Id": "ghi4",
"Text": "option4"
},
{
"Id": "ghi5",
"Text": "option5"
}
],
"SelectedAnswerId": null
}
]
}
};
Required Format:
var responseQuestions = {
"error": false,
"message": "Success",
"result": {
"Questions": [{
"Id": "131a",
"Text": "In what county do you live?",
"Answers": [{
"Id": "abc1",
"Text": "option1"
},
{
"Id": "abc2",
"Text": "option2"
},
{
"Id": "abc3",
"Text": "option3"
},
{
"Id": "abc4",
"Text": "option4"
},
{
"Id": "abc5",
"Text": "option5"
}
],
**"SelectedAnswerId": "abc2"**
},
{
"Id": "132a",
"Text": "Which zip code has ever been a part of your address?",
"Answers": [{
"Id": "def1",
"Text": "option1"
},
{
"Id": "def2",
"Text": "option2"
},
{
"Id": "def3",
"Text": "option3"
},
{
"Id": "def4",
"Text": "option4"
},
{
"Id": "def5",
"Text": "option5"
}
],
**"SelectedAnswerId": "def1"**
},
{
"Id": "133a",
"Text": "What was the original amount of your most recent mortgage?",
"Answers": [{
"Id": "ghi1",
"Text": "option1"
},
{
"Id": "ghi2",
"Text": "option2"
},
{
"Id": "ghi3",
"Text": "option3"
},
{
"Id": "ghi4",
"Text": "option4"
},
{
"Id": "ghi5",
"Text": "option5"
}
],
**"SelectedAnswerId": "ghi2"**
}
]
}
};
Now I need to submit this answer with the same above mentioned format along the "SelectedAnswerId" value(in the above mentioned array "SelectedAnswerId" is null and now I have to include the original selected ans Id based on questions ).
I have tried to fetch all the selected ans id in a array and attached the same in jsfiddle but am unable to proceed on how to append this ans id in the existing array based on questions. How to achieve this ?
Try the following loops:
$('input[type="radio"]:checked').each(function() {
var questionId = $(this).closest('.radioGroup').prev().attr('id');//get the question id
var answerId = this.id;//get the answer id
$.each(responseQuestions.result.Questions, function(i, v) {//loop each question
if (v.Id == questionId) {
$.each(v.Answers, function(ind, val) {//loop each answer
if (val.Id == answerId) {
responseQuestions.result.Questions[i]['SelectedAnswerId'] = answerId;//save the answer
}
});
}
});
});
console.log(responseQuestions);
demo:https://jsfiddle.net/mj3gvd5e/1/
Note: you need to change your question id to remove or add the a to be consistent both in the page and in the json
You have to find index based on question id and then set answerid at specific index
var index = responseQuestions.result.Questions.findIndex(function(val){
return val.Id === yourQuestionid;
})
responseQuestions.result.Questions[index].SelectedAnswerId = youranswerID;
First of all you need to have your main question id and Ans id into same array as given fiddle by Madalin jsfiddle.net/6q9mct68
second you get this array, you can loop through your first array and replace the string by compairing Id,