I have an App using Angularjs v1.69
I Get a Json Response of Time Slot
The below is the Current Code:
$scope.TimeSlotList = JSON.parse(localStorage.getItem("TimeSlots"));
Console.log($scope.TimeSlotList);
Output:
[
{
"id": 1,
"time": "7am - 10am"
},
{
"id": 2,
"time": "10am - 1pm"
},
{
"id": 3,
"time": "1pm - 4pm"
},
{
"id": 4,
"time": "4pm - 7pm"
},
{
"id": 5,
"time": "7pm - 10pm"
}
]
and this is done in the partial
<div class="col-md-6">
<div class="form_pad20">
<label>Prefered Time</label>
<div class="clearfix">
<div class="form-field field-destination">
<div class="radio-checkbox display_inline" ng-repeat="x in TimeSlotList">
<input id="check-{{x.id+9}}" type="checkbox" class="checkbox" ng-model="TimeSlotList[$index]">
<label for="check-{{x.id+9}}">{{x.time}}</label>
</div>
</div>
</div>
</div>
</div>
The Required output is Whichever Checkbox is selected i want that value
For Ex: if the user select time slot 2 and 3
i want to send 23 to the backend
i.e Timeslot-2 and Timeslot-3 should return true
or something else i want output as
var FinalTime="23";
Trying to figure out from last 2 days
But After Few Atempts basically th best solution was
ng-model="TimeSlot-{{x.id}}"
but this throughs error
Error: [ngModel:nonassign] Expression 'ScdItem.TSlot(x.id)' is non-assignable.
please can anybody help me ?
Change the TimeSlotList so that it contains a selected field. The initial value can be set to false.
$scope.TimeSlotList = JSON.parse(localStorage.getItem("TimeSlots"));
$scope.TimeSlotList.forEach(item => item.selected = false);
Then bind the selected field to the corresponding checkboxes using ng-model:
<input id="check-{{x.id+9}}" type="checkbox" class="checkbox" ng-model="x.selected">
This will change the selected's value based on checkbox is checked/not checked. When you send the data to the server, you can extract the IDs of the slots based on the value of selected field, like this:
var selectedSlots = $scope.TimeSlotList
.filter(slot => slot.selected) // Get all the selected slots
.map(slot => slot.id) // Extract IDs of the slots
.join(''); // Join the IDs to form a string
This way selectedSlots will contain the IDs of the slots selected.
<div class="col-md-6">
<div class="form_pad20">
<label>Prefered Time</label>
<div class="clearfix">
<div class="form-field field-destination">
<div class="radio-checkbox display_inline" ng-repeat="x in TimeSlotList">
<input id="check-{{x.id+9}}" type="checkbox" class="checkbox" ng-model="x.id" ng-change="checkTimeslot(x.id)">
<label for="check-{{x.id+9}}">{{x.time}}</label>
</div>
</div>
</div>
</div>
Related
I'm developing an application using Angular 6. I have a big problem.
Using a template-driven form I would like that the item selected in a radio button can be sent when I press the submit button.
It's all right when I work with <input type="text" [(ngModel)] = "value" /> (value is a data field of my component), but if I try with this:
<div class="form-group">
<div *ngFor = "let option of options">
<div class="radio">
<input type = "radio"
name = "radio"
[(ngModel)] = "value"
/>
<label for="{{option.id}}">{{option.id}}</div>
</label>
</div>
</div>
</div>
The result is a bug! I can't even click the multiple buttons by moving the selector! Everything is stuck! Obviously it does not work with the form.
If I remove [(ngModel)] = "value" graphically it works, but without ngModel directive if I enter this code inside a template-driven form that uses (ngSubmit) it does not work.
Thanks a lot.
You are missing a value for each of the radio buttons so the binding does not work correctly. It is unable to determine which input should be checked so none of them get checked. Update the template to be something like:
<div *ngFor="let option of options">
<div class="radio">
<input type="radio"
name="radio"
id="radio-{{option.id}}"
[(ngModel)]="value"
[value]="option.value"
/>
<label for="radio-{{option.id}}">{{option.id}}
</label>
</div>
Stackblitz Demo
Radio buttons work different. To need to add a value to make it work. If you want to assign a value from angular use [value].
I have make it running in an example of stackblitz:
<div class="form-group">
<div *ngFor="let option of options; let i=index">
<div class="radio">
<input type="radio" id="{{option.id}}" name="radio{{i}}" [(ngModel)]="option.value" [value]="option.id" />
<label for="{{option.id}}">{{option.id}}</label>
</div>
</div>
</div>
<hr>
<h2>Values for options</h2>
<ul>
<ng-container *ngFor="let option of options; let i=index">
<li *ngIf="option.value !== ''">Value for {{option.id}}: {{option.value}}</li>
</ng-container>
</ul>
Component
value: any;
options = [
{
id: "test1",
value: ''
},
{
id: "test2",
value: ''
},
{
id: "test3",
value: ''
}];
Extension/Hints:
You can even use [(ngModel)] = "value" to assign the last selected value to value.
Give these radio buttons the same name name="radio" to ensure that only one of this group can be selected.
Inside the ts file :
radio_button_value = null;
box_options = [
{
"name": "Word",
"value": "word",
},
{
"name": "Line",
"value": "line"
},
]
Inside the html file:
Do notice of the tag 'name', it would we a great concern inside another for loop.
<div *ngFor="let box_opt of box_options; let i=index">
<input name="option-{{i}}" type="radio" [value]="box_opt.value" [(ngModel)]="radio_button_value">
{{box_opt.name}}
<br>
</div>
I am working an edit form, it happens that I have several options to choose, these options are obtained by ajax with axios and I assign them to the variable permisos of the component that later renders through a v-for, the checked elements I have them in a array selected that is assigned to the vue-model as follows
<div class="row">
<div v-for="permiso in permisos" class="col-md-5 col-12 col-sm-5" >
<input type="checkbox" :value="permiso.id"
class="form-control" :id=permiso.id
v-model="selected" :checked=selected.filter(e => e.id === permiso.id).length > 0 > {{ permiso.name}}
</div>
</div>
later I make another ajax call to know what options I had before editing the item to know what options or checkbox I will assign the checked attribute, this is where I have problems do not check correctly.
axios.get('api/allpermisos')
.then(response =>{
this.permisos = response.data; //dataok
})
if(this.action===2){
axios.get('api/allpermisos/'+ this.dataobject.id)
.then(response =>{
this.selected = response.data;//data ok
})
}
How can I do so that when I get the ajax call from the options already selected, the attribute checked is assigned automatically and those that are not, are not assigned. try with includes but I do not have the desired result?
The code works correctly if I remove the v-model. Why is this happening?
<input type="checkbox" :value="permiso.id" class="form-control"
:id=permiso.id :checked=selected.filter(e => e.id === permiso.id).length > 0 > {{ permiso.name}}
You don't need both v-model and :checked. v-model is a two way binding.
https://jsfiddle.net/bbsimonbb/eywraw8t/15613/
<div v-for="permiso in permisos" class="col-md-5 col-12 col-sm-5" >
<input type="checkbox" :value="permiso.id"
class="form-control" :id=permiso.id
v-model="selected"> {{ permiso.name}}
</div>
Consider creating a component for your input. Form inputs inside a v-for rapidly gets complicated.
You need to keep their ids in "selected" array, you are probably keeping whole objects which didn't work from what I checked.
HTML:
<div id="app">
<div class="row">
<div v-for="permiso in permisos" class="col-md-5 col-12 col-sm-5" >
<input type="checkbox" :value="permiso.id"
class="form-control" :id=permiso.id
v-model="selected" :checked=selected.includes(permiso.id)> {{ permiso.name}}
</div>
</div>
</div>
Vue:
new Vue({
el: '#app',
data() {
return {
selected: [2, 4],
permisos: [{id: 1, name: "test1"}, {id: 2, name: "test2"}, {id: 3, name: "test3"}, {id: 4, name: "test4"}]
}
}
})
https://jsfiddle.net/eywraw8t/15555/
This works.
If you are getting object array as response, you could do this:
this.selected = response.data.map(obj => obj.id);
I try and try but I cant get it working.. I do a ng-repeat creates me some DIVs out of a $scope-object:
<div class="col-2 currBit" ng-repeat="one in crypto">
<div class="currBitTitle">{{one.shortName}}</div>
<div class="currBitTitleSub">
<div class="currLogo currLogo_{{one.shortName}}"></div><br/>
{{one.longName}}<br/>
</div>
<div class="currBitInput">
<input type="number" placeholder="Your amount of {{one.shortName}}" ng-model="one.shortName" >
</div>
</div>
now, in the inputfield of each created DIV I need to set a ng-model, so my app can use the input-vlaues of the dynamicly generated input-fields
in this code posted, when the data is bound to the <div class="currBitTitle">{{one.shortName}}</div> ?? .. why is that? How can I get this managed?
it would be nice to have a individual prefix like ng-model="myfoobar_{one.shortName}"
is that even possible?
You can try to use like below code also check this fiddler link for your example scenario.
Template:
<input type="number" ng-model="myfoobar_[one.shortName]">
Controller:
$scope.myfoobar_ = {};
$scope.crypto = [{
"shortName": "Name1",
"longName": "Name One"
}, {
"shortName": "Name2",
"longName": "Name Two"
}];
I'm currently experimenting with Angular and I have an issue, I have a set of questions from my API, some of them rely on other ones to be checked as yes when its a radio button question and will have a value in the property called ReliesOnID.
Once I check yes, the question which relies on the current one being checked needs to show.
I come from a jQuery background so I would do a function passing in the reliesonid as that will be the question number and do something like $('#question' + reliesonid').show().
How can I make the radio buttons show the other question when I click yes as they are in a repeat? Been stuck on this for ages so help is greatly appreciated. Here is my code below:
<div id="question{{question.Number}}" ng-repeat="question in questions" ng-class="question.ReliesOnID == null ? 'here' : 'hidden'">
<div ng-if="question.QuestionTypeID == 3" >
<div class="row">
<div class="col-xs-12">
<h5>{{question.Question}}</h5>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<div class="col-xs-4"></div>
<div class="col-xs-8">
<input type="radio" value="yes" name="{{question.Number}}" /><label>Yes</label>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<div class="col-xs-4"></div>
<div class="col-xs-8">
<input type="radio" value="no" name="{{question.Number}}" /><label>No</label>
</div>
</div>
</div>
</div>
<div ng-if="question.QuestionTypeID == 1">
<div class="row">
<div class="col-xs-12">
<h5>{{question.Question}}</h5>
</div>
</div>
<div class="row">
<div class="col-xs-4">
<input type="text" class="form-control" />
</div>
</div>
</div>
</div>
EDIT: Data structure is:
{
"Active": true,
"Comments": false,
"DecimalPlaces": 0,
"F": false,
"FP": false,
"Grouped": null,
"ID": 20500,
"Length": false,
"MP": true,
"Multiline": false,
"Number": 45,
"NumericOnly": false,
"Optional": false,
"Question": "How long ago was the treatment?",
"QuestionID": 45,
"QuestionSectionID": 2,
"QuestionTypeID": 2,
"QuestionnaireID": 298,
"ReliesOnAnswer": true,
"ReliesOnID": 44,
"Weight": false
}
You need to use ng-model for your answers like:
<input type="radio" value="yes" ng-model="question.Answer" name="{{question.Number}}"/><label>Yes</label>
And then inside that question you could have sub questions and would just use ng-repeat.
ng-if="question.subQuestions && question.Answer !== undefined" ng-repeat="subquestion in question.subQuestions"
This will all depends on your question structure of course
EDIT
Based on your structure I would say you need an ng-if in your ng-repeat that could go something like this:
ng-if="!question.ReliesOnID || wasAnswered(question.ReliesOnID)"
In wasAnswered function you would need access to the questions array and filter for that ID and check if it was answered and return true or false
Try this snippet.
Is it something, you're looking for?
I tried to understand your question, and created an example based on your JSON data structure.
Based on the selection of particular question, it will show it's answer only.
Edit-1 : Applied Angular Element
If jQuery is available, angular.element is an alias for the jQuery function. If jQuery is not available, angular.element delegates to Angular's built-in subset of jQuery, called "jQuery lite" or jqLite.
More information angular.element
You can do eliminate jQuery from code, if you want.
You can do the set / get class in Angular by using angular.element as shown over here.
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingController', ['$scope', function($scope) {
$scope.questions = [
{
"Active": true,
"Comments": false,
"DecimalPlaces": 0,
"F": false,
"FP": false,
"Grouped": null,
"ID": 20500,
"Length": false,
"MP": true,
"Multiline": false,
"Number": 45,
"NumericOnly": false,
"Optional": false,
"Question": "How long ago was the treatment?",
"QuestionID": 45,
"QuestionSectionID": 2,
"QuestionTypeID": 2,
"QuestionnaireID": 298,
"ReliesOnAnswer": true,
"ReliesOnID": 10,
"Weight": false,
"Answer": '2 years ago'
},
{
"Active": true,
"Comments": false,
"DecimalPlaces": 0,
"F": false,
"FP": false,
"Grouped": null,
"ID": 20500,
"Length": false,
"MP": true,
"Multiline": false,
"Number": 45,
"NumericOnly": false,
"Optional": false,
"Question": "Who is God of cricket?",
"QuestionID": 45,
"QuestionSectionID": 2,
"QuestionTypeID": 2,
"QuestionnaireID": 298,
"ReliesOnAnswer": true,
"ReliesOnID": 20,
"Weight": false,
"Answer": 'Sachin Tendulkar'
}
]
//Function when radio button clicked
$scope.flagChange = function(){
var reliesId = angular.element(event.target).attr('data-reli-id');
var value = angular.element(event.target).attr('data-value');
//Based on the condition it will show / hide the respective element
if(value == "yes")
{
$('#'+reliesId).removeClass('hide').addClass('show');
}
else
{
$('#'+reliesId).removeClass('show').addClass('hide');
}
}
}]);
.show
{
display: block;
}
.hide
{
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="GreetingController">
<div ng-repeat="question in questions track by $index">
{{question.Question}}
<input type="radio" name="Flag_{{$index}}" ng-click="flagChange($event)" data-value="yes" data-reli-id='{{question.ReliesOnID}}' />Yes
<input type="radio" name="Flag_{{$index}}" ng-click="flagChange($event)" data-value="no" data-reli-id='{{question.ReliesOnID}}' />No
<span ng-show="custom_$index">{{question.Answer}}</span>
<br/>
<div id="{{question.ReliesOnID}}" class="hide">
Question based on ReliesOnID : {{question.ReliesOnID}}
</div>
<br/>
</div>
</div>
I dont like to use ng-if as that adds and removes the elements to the DOM. Below is a link to the ng-show/hide and a tutorial on how to use it on scotch.io.
https://docs.angularjs.org/api/ng/directive/ngShow
https://scotch.io/tutorials/how-to-use-ngshow-and-nghide
So a quick example would be below where the div element will only show when the variable is_active is true(this check can work with booleans or a text check). And this variable can be set in the controller or in the view. You dont need to toggle this. The div will automaticall hide when the evaluation is not true; so no need for a ng-hide and ng-show on the same element unless you are checking against multiple conditions.
<input type="radio" ng-model="question.subQuestion" value="true"> <br/>
<input type="radio" ng-model="question.subQuestion" value="false"> <br/>
<div ng-show="question.subQuestion">
// Your subQuestion code comes here
</div>
Edit: based on comments below and provided data structure:
If assumed that you want to iterate just that questions which are parent and doesn't related on anything at start. Related should be display only when ratio is set on true:
So replace yourng-repeat with ng-repeat-start which will make you able iterate multiple divs not just on where ng-repeat is on.
In your <div> element add :
<input type="radio" ng-model="question.subQuestion" value="true"> <br/>
<input type="radio" ng-model="question.subQuestion" value="false"> <br/>
After that make another <div> below which will display your related questions. It can looks like:
// ng-if here to display only when radio was set to true
<div class="relatedQuestion" ng-repeat-end ng-if="question.subQuestion">
<div ng-repeat="relatedQ in getRelatedQuestion(question.Number)">
// Here you display your related questions
</div>
</div>
So in your controller you need to add a function:
function getRelatedQuestion(number) {
// logic comes here which filter question
// which have property relatedOnId === number;
// it should be an array of objects to iteratee over it.
}
What you present as an option from JQUERY is possible in angular as well.
However there is prolly even easier solution.
In your ng-repeat solution you replace your radio input with something like:
<input type="radio" ng-model="question.subQuestion" value="true"> <br/>
<input type="radio" ng-model="question.subQuestion" value="false"> <br/>
And then below you add this:
<div ng-if="question.subQuestion">
// Your subQuestion code comes here
</div>
Everything will be inside of your ng-repeat and should work correctly without additional logic in controller.
Let's say I have a form, which iterates over some fields.
I want to wrap some fields in a container, so that I can split the form into sections.
I have tried to put field_open = true under the item I want to start opening the div, and then field_close = true under the last field in that container and then I repeat this process.
<form name="{{form.form_name}}" id="{{form.form_id}}">
<div ng-if="field.field_open == true" class="halfCol">
<div ng-repeat="field in form.form_fields">
<div class="{{field.field_class}}">
<field-directive field="field"></field-directive>
</div>
</div>
</div ng-if="field.field_close == true">
</form>
Obviously this doesn't work, but I'm wondering how I can achieve this?
The below HTML is how it should be rendered:
<form name="test" id="test">
<div class="halfCol">
<label for="apple">Apple</label>
<input type="text" name="apple" id="apple" />
<label for="fruit">Fruit</label>
<input type="text" name="fruit" id="fruit" />
</div>
<div class="halfCol">
<label for="dog">Dog</label>
<input type="text" name="dog" id="dog" />
</div>
</form>
The above html should be drawn from the following data.
var data = {
"form_name": "test",
"form_fields": [
{
"field_title": "Apple",
"field_open" : false
"field_open" : true
}{
"field_title": "Fruit",
},{
"field_title": "Dog",
"field_close" : true
"field_open" : true
}
]}
I'm more or less looking for a way to wrap certain elements in the same field scope.
What will the decision to separete the fields in sections depend on?
If the decision depends on some aspect of presentation, I think you don't need to use model data as you do. I mean you could write simple html without ng-repeat directives.
If you insist to use model data, your model structure will be like below.
var data = {
"form_name": "test",
"form_sectinons": [
{
"section_title": "section 1",
"fields": [
{"field_title": "Apple"},
{"field_title": "Fruit"},
]
},
{
"section_title": "section 2",
"fields": [
{"field_title": "Dog"},
]
}
]
}
And Html will be like below.
<form>
<div ng-repeat="section in data.form_sections">
<div ng-repeat="field in section.fields" class="halfCol">
<field-directive field="field"></field-directive>
</div>
</div>
</form>
I'm not sure quite what you are trying to do but you should do like this:
<form name="{{form.form_name}}" id="{{form.form_id}}">
<div ng-if="field.field_open == true && field.field_close == true" class="halfCol">
<div ng-repeat="field in form.form_fields">
<div class="{{field.field_class}}">
<field-directive field="field"></field-directive>
</div>
</div>
</div>
</form>