I am trying to get a two way binding for a checkbox in an inner loop using JsViews
Not sure if this is possible.
<div id="targetSelection"></div>
<script id="targetItem" type="text/x-jsrender">
<b>{^{:text}}</b>
<div id="answers_{^{:fieldName}}" class='collapse'>
{^{for answers ~fieldName=fieldName}}
<label>
<input type="checkbox" data-fieldName="{{>~fieldName}}" data-index="{{:index}}" data-link="{:selected}" checked="{^{:selected}}" /> {{:text}} : {^{:selected}}
</label>
<br /> {{/for}}
</div>
<br />
</script>
and the JS code:
var target = [{
"fieldName": "GENDER",
"text": "Gender",
"answers": [{
"index": 1,
"text": "Male"
}, {
"index": 2,
"text": "Female"
}, ]
}, {
"fieldName": "AGE",
"text": "Age",
"answers": [{
"index": 1,
"text": "15-19"
}, {
"index": 2,
"text": "20-24"
}, {
"index": 3,
"text": "25-29"
}, {
"index": 4,
"text": "30-34"
}, {
"index": 5,
"text": "35-39"
}, {
"index": 6,
"text": "40-44"
}, {
"index": 7,
"text": "45+"
}, ]
}];
$.each(target, function(questionIndex, question) {
$.each(question.answers, function(answerIndex, answer) {
answer.selected = true;
});
});
$("#targetSelection").html($.templates("#targetItem").render(target));
http://jsfiddle.net/22q7z9n9/
I am also trying to fire an event when the checkbox is changed
Thanks in advance
Did you check the JsViews docs? You are calling the render() method, not the link() method, and are using jsrender.js not jsviews.js!
So you need to load jsviews.js as in Example page, and then write: $.templates("#targetItem").link("#targetSelection", target);
See http://www.jsviews.com/#jsv-quickstart
Once you have read the basics, you can continue along the lines of:
{^{for answers}}
<label>
<input type="checkbox" data-link="selected" />
{{:text}} : {^{:selected}}
</label>
<br />
{{/for}}
For the event, there are a few options including to bind directly to the input change event, or listen to observable changes in your data etc. (http://www.jsviews.com/#observe). See the examples...
Here is a working version http://jsfiddle.net/28Lezc9m/4/.
I also changed: <div id="answers_{^{:fieldName}}" class='collapse'> to <div data-link="id{:'answers_ + fieldName" class='collapse'> - as explained in this tutorial sequence.
Related
I am making angular dynamic form with form-elements loaded through JSON..
The form element generation are working fine, but i am in the need of change of form elements based on options selected from dropdown..
JSON that generates form-elements
jsonData: any = [
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "project_name",
"label": "Project Name",
"type": "text",
"value": "",
"required": false,
"minlength": 3,
"maxlength": 20,
"order": 1
},
{
"elementType": "dropdown",
"key": 'project',
"label": 'Choose option to display',
"options": [
{ "key": 'description', "value": 'Show Project Description' },
{ "key": 'level', "value": 'Show Project Level' },
{ "key": 'members', "value": 'Show Project Members' }
],
"order": 2
},
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "project_desc",
"label": "Project Description",
"type": "text",
"value": "",
"order": 3
},
{
"elementType": "dropdown",
"key": 'project_level',
"label": 'Choose Project Level',
"options": [
{ "key": 'low', "value": 'Low' },
{ "key": 'medium', "value": 'Medium' },
{ "key": 'high', "value": 'High' }
],
"order": 4
},
{
"elementType": "dropdown",
"key": 'project_members',
"label": 'Choose Project Member',
"options": [
{ "key": 'developer', "value": 'Developer' },
{ "key": 'leader', "value": 'Leader' },
{ "key": 'manager', "value": 'Manager' }
],
"order": 5
}
];
Based on the above JSON, the elements are generated..
Here you can see that Order 1 has textbox with project name which has no changes.
Then in next we have a dropdown with key as project, from here only the requirement starts..
In options, if i choose Show Project Description, then the Project Description textbox needs to be displayed and other two project_level and project_members needs to be in hidden format..
Likewise if i choose Show Project Level then the Project Level dropdown alone needs to be displayed and the Project Description and Project Members needs to be in hidden..
In the same way for Project Members..
So how to change the form-elements based on the selection of project dropdown values??
The working example for the same was here https://stackblitz.com/edit/angular-x4a5b6-5ys5hf
Kindly help me to hide the other elements based on the selection from the project dropdown using angular dynamic form alone..
As #benshabatnoam say the only thing you need is change you dinamic-form-question to include some like
<div [formGroup]="form" *ngIf="?????">
You can use a condition like #Benshabatnoam say, but I suggest you some more "parametrizable"
Imagine your json has a new property "visible" that was an object with two properties, field and value. So, your element "project_desc" can be like
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "project_desc",
"label": "Project Description",
"type": "text",
"value": "",
"order": 3,
"visible":{"field":"project","value":'description'} //<--add this "property"
},
So the dinamic-form-question can be like
<div [formGroup]="form"
*ngIf="!question.visible ||
form.get(question.visible.field).value==question.visible.value">
...
</div>
See that I include the condition (!question.visible) so, if you don't give the property "visible" to one field, this field is showed always.
Well, you must work some more, you must change question-base.ts to admit this new property
export class QuestionBase<T> {
value: T;
...
visible:any; //<--ad this property
constructor(options: {
value?: T,
...
visible?:any, //In constructor include "visible" too
..
}){
this.value = options.value;
...
this.visible = options.visible;
}
You can see your forked stackblitz
You need to make few changes to your code.
Change the json so that the options key will match the controls key.
...
{
"elementType": "dropdown",
"key": 'project',
"label": 'Choose option to display',
"options": [
{ "key": 'project_desc', "value": 'Show Project Description' },
{ "key": 'project_level', "value": 'Show Project Level' },
{ "key": 'project_members', "value": 'Show Project Members' }
],
"order": 2
},
{
"elementType": "textbox",
"class": "col-12 col-md-4 col-sm-12",
"key": "project_desc",
"label": "Project Description",
"type": "text",
"value": "",
"order": 3
},
...
In your form add a *ngIf to the app-question component that will execute a function passing it the question, and this function will holding the logic for hiding the given question.
<app-question *ngIf="isShowQuestion(question)" [question]="question" [form]="form">
</app-question>
The function logic would check if the question is one of the controls you want to hide, and if so it will check the value of the dropdown 'option to display' for match, if match it will show the question else it will hide the question.
isShowQuestion(question: QuestionBase<any>): boolean {
// If one of the controls you want to hide
if (question.key === 'project_desc' ||
question.key === 'project_level' ||
question.key === 'project_members') {
// if the option to display have value and it is this question that show it else don't show it
return !this.form.controls['project'].value ||
this.form.controls['project'].value === question.key;
} else { // if not, always display
return true;
}
}
I've forked your stackblitz project, so you can see it in action here.
Recently I've been trying to figure out how those Reactive Forms works. Basic examples (no nesting etc.) are understandable however if I have a form structure like this with checkboxes:
{
"username": "",
"damnIt": "",
"checkboxes": [
{
"checked": false,
"name": "Checked1",
"value": 10
},
{
"checked": false,
"name": "Checked1",
"value": 11
},
{
"checked": false,
"name": "Checked1",
"value": 12
}
]
}
How should I render it on the template in order to change the "*checked" value (true | false)?
You could do something like this:
<form #theForm="ngForm" (ngSubmit)="submitForm(theForm.value)">
<div *ngFor="let cb of data.checkboxes">
<label>
<input type="checkbox" [name]="cb.name" [(ngModel)]="cb.checked">{{cb.value}}
</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<pre>{{data.checkboxes|json}}</pre>
See Plunkr: https://plnkr.co/edit/MpSO21fIJq1DtJoXmE3V?p=preview
In my Angular1.x app, my models maps to my radio selection correctly, however the radio button itself is not selected except for the very last one. Not really sure what the problem is. I created a very small example below to illustrate this behaviour. Any help is greatly appreciated.
http://plnkr.co/edit/dgGCvtOEb9WKTNtQHjqd?p=preview
angular.module('todoApp', [])
.controller('TodoListController', function() {
var todoList = this;
todoList.questions = [{
"category": "Movies",
"questions": [{
"title": "M1",
"score": "4",
},
{
"title": "M2",
"score": "2",
}
]
},
{
"category": "Foods",
"questions": [{
"title": "F1",
"score": "3",
},
{
"title": "F2",
"score": "4",
}
]
},
{
"category": "Sports",
"questions": [{
"title": "S1",
"score": "5",
}]
}
];
});
<!doctype html>
<html ng-app="todoApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<script src="todo.js"></script>
<link rel="stylesheet" href="todo.css">
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.0.4/css/bootstrap-combined.min.css">
</head>
<body>
<h2>Todo</h2>
<div ng-controller="TodoListController as todoList">
<div ng-repeat="(ccKey, cc) in todoList.questions">
<hr/>
<div>
<b style="color: red;">Category</b> : {{cc.category}}
</div>
<div ng-repeat="(qqKey, qq) in cc.questions">
<br/>
{{qq.title}} : Selected Score: {{qq.score}}
<br/>
<div ng-repeat="n in [].constructor(5) track by $index">
<input type="radio" ng-model="qq.score" name="q-{{ccKey}}-{{qqKey}}" value="{{$index+1}}"><br/>Score: {{$index+1}} : Group: q-{{ccKey}}-{{qqKey}}
</div>
</div>
</div>
</div>
</body>
</html>
Try removing the name attribute from your <input type="radio"> tag. This seems to be causing a conflict with what Angular is doing to manage your radio tags. I am able to see all categories selected, and the selections are still grouped within a given question.
In the Angular input[radio] docs, they do not show using a name attribute: https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
If what you want is the initial selection of the values when the page first loads,then use
ng-value="($index+1).toString()"
Since your scores are given as strings, you need to convert the number to string to match the score when you use "ng-value". Or better, you can just set your scores as integers and leave the rest of the code unchanged:
todoList.questions = [{
"category": "Movies",
"questions": [{
"title": "M1",
"score": 4,
},
{
"title": "M2",
"score": 2,
}
]
}, ....
Here is a modified plunker
Using my json file, I'm making select type of questions on my web app.
The code I have for my select tag is like following:
<div class="form-group" ng-class="{ 'has-error': form.$submitted && form[field.id].$invalid }" ng-if="field.type === 'select'">
<label for="{{field.id}}">{{field.title}}</label>
<br>
<select ng-model="formData[field.id]" ng-value="{{value.title.id}}" ng-options="value as value.title for value in field.values">
<option disabled selected value> -- select an option -- </option></select>
<p class="form-group-note" ng-if="field.info" ng-bind="field.info"></p>
<div ng-show="form.$submitted" ng-cloack>
<span class="help-block" ng-show="form['{{field.id}}'].$error.required" ng-if="field.validations.required">Please enter a value, this field is required</span>
</div>
</div>
I have a json file like following:
{
"groups": [
{
"id": "10_8_group",
"title": "Existence",
"index": 60,
"part": 10,
"sections": [
{
"id": "10_8_section",
"title": "Existence",
"fields": [
{
"id": "10_8_labor_organization",
"title": "8. Does it exist?",
"info": "Always select \"No\"",
"type": "select",
"size": {
"width": 100,
"height": 1
},
"values": [
{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No. If no, proceed to Part 9. and type or print your explanation."
}
]
}
]
}
]
}
]
}
when the data is being saved in localStorage(Angular's frontend model), it saves the data as "10_8_labor_organization":{"id":1,"title":"Yes"}}
However, I would like to save this as
"10_8_labor_organization":"Yes"
How can I accomplish this??
write your code like value.id as value.title for value in field.values
I want to generate a bootstrap grid with columns: calss = "col-lg-6" and "col-lg-3".
here is the html:
<div class="container">
<div class="row">
<div class="col-lg-3">
<img src="../dist/images/test-info.png" alt="TEST-PLAN"/>
</div>
<div class="col-lg-6">
<img src="../dist/images/test-details.png" alt="TEST-DETAILS"/>
</div>
<div class="col-lg-3">
<img src="../dist/images/test-stats.png" alt="TEST-STATS"/>
</div></div></div>
However I would like to generate the above grid dynamically, in such a way that when class ="col-lg-6", it should display the 'TEST-STATS' image with its correct position mentioned in the json below:
var data = [
{
"widgetId": "widget_0",
"title": "Test Info",
"description": "",
"type": "info",
"dataType": "TEST_INFO",
"position": {
"col": 1,
"row": 1,
"size_x": 1,
"size_y": 4
}
},
{
"widgetId": "widget_1",
"title": "Test Details",
"description": "",
"type": "info",
"dataType": "TEST_DETAILS",
"position": {
"col": 2,
"row": 1,
"size_x": 2,
"size_y": 4
}
},
{
"widgetId": "widget_2",
"title": "Test Stats",
"description": "",
"type": "info",
"dataType": "TEST_STATS",
"position": {
"col": 4,
"row": 1,
"size_x": 1,
"size_y": 4
}
}]
Every image has its own position to render, so a conditional statement like:
if(class=="col-lg-6")
{//display image as 'TEST-DETAILS'}
how to create a dynamic template and write a javascript function to loop for the classes and display the image according to the position?
Thanks!!
There are a lots of example on internet.
One of the best that I used is : http://www.cssgrid.co/
Very light and powerful to work with.
EDIT: since 2017, I'm using the CSS flex attributes. In my opinion, the CSS Grid frameworks are not really helpful those days.
You can use the jQuery class selector in order to select the element with class col-lg-6 and then set the attribute alt to TEST-DETAILS
ex. $(".col-lg-6").attr("alt", "TEST-DETAILS")