Assigning unique models and ids to checkboxes within ng-repeat - javascript

I'm trying to understand data-binding with AngularJs and I'm working on a simple form that uses ng-repeat to render a set of accordions. The headings of each accordion has a status box that is red by default, yet when the accordion is expanded, checking the checkbox within should turn the status box green.
The problem I'm having is that when I check a checkbox, it turns the status box of each accordion heading green; not just the status box relevant to the checkbox.
I know I need to assign a unique model to each status box/checkbox but I'm unsure how. I've seen some examples with $index but I haven't been able to apply it to my problem.
The HTML is as follows:
<ul class="radio-accordion">
<li class="radio-accordion-item" ng-repeat="animal in ctrl.animalTypes">
<input id="input{{$index + 1}}" type="checkbox" name="input" />
<div class="radio-accordion-header grey">
<div class="radio-accordion-header-left">
<div class="radio-accordion-header-title-wrapper">
<span class="status-led {{ctrl.checkedStatus}}"></span>
<h1 class="radio-accordion-header-title text-blue">{{animal.name}}</h1>
</div>
</div>
<div class="radio-accordion-header-right"></div>
<label class="expander-blue" for="input{{$index + 1}}"></label>
</div>
<div class="radio-accordion-body white">
<div class="padd-10 marg-left40">
<div class="toolbar-flex marg-top-10 marg-bott0">
<input class="restyled"
id="input{{$index + 1}}"
name="input"
type="checkbox"
ng-model="ctrl.checkedStatus"
ng-change="ctrl.setConsent()"
ng-true-value="'green'"
ng-false-value="'red'" />
<label class="restyled-label"
for="input{{$index + 1}}"><em>I like this animal</em></label>
</div>
</div>
</div>
</li>
`
Any help appreciated!
EDIT: This is what I did in case it helps anyone in the future!
<ul class="radio-accordion">
<li class="radio-accordion-item" ng-repeat="animal in ctrl.animalTypes" ng-model="animal.checked>
<input id="input{{$index + 1}}" type="checkbox" name="input" />
<div class="radio-accordion-header grey">
<div class="radio-accordion-header-left">
<div class="radio-accordion-header-title-wrapper">
<span ng-class="{'status-led red': animal.checked == false, 'status-led green': animal.checked == true}"></span>
<h1 class="radio-accordion-header-title text-blue">{{animal.name}}</h1>
</div>
</div>
<div class="radio-accordion-header-right"></div>
<label class="expander-blue" for="input{{$index + 1}}"></label>
</div>
<div class="radio-accordion-body white">
<div class="padd-10 marg-left40">
<div class="toolbar-flex marg-top-10 marg-bott0">
<input class="restyled"
id="input{{$index + 1}}"
name="input"
type="checkbox"
ng-model="animal.checked"
ng-change="ctrl.isChecked(animal.checked)" />
<label class="restyled-label"
for="input{{$index + 1}}"><em>I like this animal</em></label>
</div>
</div>
</div>
</li></ul>

If you aren't concerned about adding additional properties to your animal objects , or if there already exists a property in those objects that would be used as checkbox indicator just use:
ng-model="animal.SomeProperty"
An alternate way is to use a separate object and use $index as each key:
ng-model="ctrl.checkedStatus[$index]"

Related

How to use HTML template tag with jQuery?

Something strange bug is going on in my code. I want to use HTML template tag with jQuery, because all the rest of my code is jQuery, but I only found JavaScript examples with it. I tried to "translate" from JavaScript to jQuery, this is what I came up with.
$.getJSON( "../Controller/ControllerBookstore.php?show_books=true", function( data ) {
$.each( data, function( index, value ) {
// let clone = document.getElementById('table-template').content.cloneNode(true);
// clone.querySelector('#id').innerText = value.id;
// clone.querySelector('#author').innerText = value.author;
// clone.querySelector('#title').innerText = value.title;
// clone.querySelector('#isbn').innerText = value.isbn;
let clone = $("#table-template").clone(true);
$("#id",clone).text(value.id);
$("#author",clone).text(value.author);
$("#title",clone).text(value.title);
$("#isbn",clone).text(value.isbn);
//$(".container").append(clone);
$("#header").append(clone);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div id="myAlert" class="alert alert-success collapse">
<span id="alert-text"></span>
<a id="alert-close" class="close" href="#" aria-label="Close">×</a>
</div>
<div class="row" id="header">
<div class="col"><h5>ID</h5></div>
<div class="col"><h5>Author</h5></div>
<div class="col"><h5>Title</h5></div>
<div class="col"><h5>ISBN</h5></div>
<div class="col"><h5>Action</h5></div>
</div>
<template id="table-template">
<div class="row">
<div class="col" id="id"></div>
<div class="col" id="author"></div>
<div class="col" id="title"></div>
<div class="col" id="isbn"></div>
<div class="col buttons">
<button class='btn btn-info edit'>Edit</button>
<button class='btn btn-danger delete'>Delete</button>
</div>
</div>
</template>
<div class="row justify-content-center" >
<form action="" class="col-4">
<input id = "id-box" type="hidden" name="id">
<div class="form-group row">
<label class="col-4">Author</label>
<input id = "author-box" type="text" class="form-control col-8" name="author" placeholder="Enter the author of the book">
</div>
<div class="form-group row">
<label class="col-4">Title</label>
<input id = "title-box" type="text" class="form-control col-8" name="title" placeholder="Enter the title of the book">
</div>
<div class="form-group row">
<label class="col-4">ISBN</label>
<input id = "isbn-box" type="text" class="form-control col-8" name="isbn" placeholder="Enter the ISBN of the book">
</div>
<div class="form-group row">
<button id = "submit" type="submit" name="save" class="btn btn-primary col-12">Save</button>
</div>
</form>
</div>
</div>
For some reason the JavaScript code I commented out works, but it only appends "clone" to my ".container" correctly, on the next line below the form. However I want to attach it to my ".header", but it attaches next to the header, not below it. The jQuery code doesn't do anything, it doesn't attach my "clone" anywhere.
I hope I was clear. Could you please help me to find the reason of the bugs?
A few changes are needed:
The id value of the template has a hyphen which must be escaped in the selector. Two backslashes are needed in the string literal; the first is needed to actually get a backslash in the string. The remaining one will be interpreted by the selector.
Clone the row element within the template, not the template itself. However, jQuery will not know of a DOM within the template tag, so you could just take the HTML content instead of cloning, and then turn that into a jQuery object again (which produces the DOM for it).
Insert the clone just before the template
Code:
let clone = $($("#table\\-template").html()); // <--------
$("#id",clone).text(value.id);
$("#author",clone).text(value.author);
$("#title",clone).text(value.title);
$("#isbn",clone).text(value.isbn);
$("#table-template").before(clone); // <------
As others have commented, id attributes should have unique values, so your template content cannot have id properties (since it gets cloned). Use class attributes instead.
jQuery bug
Hello my friend. You are cloning the incorrect element, because your create a clone of template with the id #table-template. Please, make this change to your code:
...
let clone = $("#table-template").html();
...
The other thing, the cloned code appears next to #header and not below it because you are using a .row class. I propose to create a div below the #header, with the id="body" and append the new content inside:
...
// $("#header").append(clone);
-> $("#body").append(clone);
...
Thanks for the example.
But I don't change the id of the "collapse" div.
The rest of the objects are cloned normally.
<template id="facilities_template">
<div class="collapse">
<div class="form-check icon-check">
<input class="form-check-input" type="checkbox">
<label class="form-check-label font-14" id="facilities_name" ></label>
<i class="icon-check-1 far fa-square color-gray-dark font-20"></i>
<i class="icon-check-2 fa fa-check-square font-20 color-green-dark"></i>
</div>
<div class="mb-3"></div>
</div>
</template>
JavaScript:
let cloneFacility = $($('#facilities_template').html());
$('#facilities_name', cloneFacility).text(value.name);
$('#facilities_name', cloneFacility).attr('data-facility-id', value.id);
$('#collapse', cloneFacility).attr('id','collapse'+ value.id)
$('#facilities_template').before(cloneFacility);
$('#faсility_filter').append(cloneFacility);

jquery selecting child elements

The setup.
I am using MVC 5, and I have created a view with data sent in the form of a viewmodel.
With in this view I have rendered a List object as stacked div's, as seen below.
As you will see, I am displaying hidden fields, so that the viewModel send back the data to the controller on submit.
<div class="row item-row">
<div class="small-4 columns">
objType
</div>
<div class="small-6 columns">
<input id="object_0__Id" name="object[0].Id" type="hidden" value="999999">
<input id="object_0__Reference" name="object[0].Reference" type="hidden" value="myRef">myRef
<input id="object_0__RecordChanged" name="object[0].RecordChanged" type="hidden" value="NoChange">
</div>
<div class="small-2 columns remove-item">
<button class="button tiny expand centre button-gray" onclick="javascript: RemoveItem(999999);">Remove</button>
</div>
</div>
<div class="row item-row">
<div class="small-4 columns">
objType
</div>
<div class="small-6 columns">
<input id="object_1__Id" name="object[1].Id" type="hidden" value="000001">
<input id="object_1__Reference" name="object[1].Reference" type="hidden" value="myRef">myRef
<input id="object_1__RecordChanged" name="object[1].RecordChanged" type="hidden" value="NoChange">
</div>
<div class="small-2 columns remove-item">
<button class="button tiny expand centre button-gray" onclick="javascript: RemoveItem(000001);">Remove</button>
</div>
</div>
Ok, so the javascript function RemoveItem is:
function RemoveItem(id)
{
event.preventDefault();
var element = $(event.target).closest('.item-row');
$(element).closest('DeedReference_0__RecordChanged').val('Deleted'); ***** This is what I am trying to do.
$(element).hide();
}
From the above, when I click on say RemoveItem(00001), the variable element contains the following:
<div class="small-4 columns">
objType
</div>
<div class="small-6 columns">
<input id="object_0__Id" name="object[0].Id" type="hidden" value="000001">
<input id="object_0__Reference" name="object[0].Reference" type="hidden" value="myRef">myRef
<input id="object_0__RecordChanged" name="object[0].RecordChanged" type="hidden" value="NoChange">
</div>
<div class="small-2 columns remove-item">
<button class="button tiny expand centre button-gray" onclick="javascript: RemoveItem(000001);">Remove</button>
</div>
The value I need to update is object[0].RecordChanged, but at this moment in time, I do not know the index value. So I was planning on using the ends with selector, but am not able to get it to work.
I have got as far as:
$(event.target).closest('.item-row').children()[1]
But this gives me the div, since I have tried:
$(event.target).closest('.item-row').children()[1].Find('Id*"__RecordChanged"')
$(event.target).closest('.item-row [id*="RecordChanged"]')
$(event.target).closest('.item-row:[id*="RecordChanged"])
And using the variable
$(element [id*="RecordChanged"])
$(element [id$="RecordChanged"])
UPDATE
Fixed bug in code that was suggesting that I was looking at the wrong index.
Also, If I click the remove button for RemoveItem(000001), I am trying to update the value object_0__RecordChanged.
Changed view model to have an index property. Then changed placed the HTML.EditorFor within a foreach loop enabling me to populate the index property before it is rendered out.
Then the code was changed from:
function RemoveItem(id)
{
event.preventDefault();
var element = $(event.target).closest('.item-row');
$(element).closest('DeedReference_0__RecordChanged').val('Deleted'); ***** This is what I am trying to do.
$(element).hide();
}
to:
function RemoveItem(id)
{
event.preventDefault();
var recordChanged = '#object_' + id + '__RecordChanged';
$(recordChanged).val('Deleted');
var element = $(event.target).closest('.item-row');
$(element).hide();
}
Much simpler!

Can I set a checkbox to be enabled or disabled based on whether multiple checkboxes are checked?

So I have multiple row of check boxes like the picture below
I want to make the add,edit and delete checkbox in the same row be disabled when the most left checkbox in the same row is checked using jquery, i try using solution in here solution, but this solution only work for 1 group of checboxes, i'm gonna have a lot of checkboxes group, i prefer using loop statement for this case, but i cant come up with any solution.
here's my html code:
<div class="row">
<div class="col-sm-5"><input type="checkbox" name="aauth100" value="auth100" id="auth100" onclick ="togAuth1()">New Member + Kit Purchase</input></div>
<div class="col-sm-2"><input type="checkbox" name="aaddAuth100" value="addAuth100" id="addAuth100">Add</input></div>
<div class="col-sm-2"><input type="checkbox" name="aeditAuth100" value="editAuth100" id="editAuth100">Edit</input></div>
<div class="col-sm-2"><input type="checkbox" name="adelAuth100" value="delAuth100" id="delAuth100">Delete</input></div>
</div>
<div class="row">
<div class="col-sm-5"><input type="checkbox" name="auth101" value="auth101" id="auth101">New Member Registration</input></div>
<div class="col-sm-2"><input type="checkbox" name="addAuth101" value="addAuth101" id="addAuth101">Add</input></div>
<div class="col-sm-2"><input type="checkbox" name="editAuth101" value="editAuth101" id="editAuth101">Edit</input></div>
<div class="col-sm-2"><input type="checkbox" name="delAuth101" value="delAuth101" id="delAuth101">Delete</input></div>
</div>
<div class="row">
<div class="col-sm-5"><input type="checkbox" name="auth102" value="auth102" id="auth102">Member Data Maintenance</input></div>
<div class="col-sm-2"><input type="checkbox" name="addAuth102" value="addAuth102" id="addAuth102">Add</input></div>
<div class="col-sm-2"><input type="checkbox" name="editAuth102" value="editAuth102" id="editAuth102">Edit</input></div>
<div class="col-sm-2"><input type="checkbox" name="delAuth102" value="delAuth102" id="delAuth102">Delete</input></div>
</div>
<div class="row">
<div class="col-sm-5"><input type="checkbox" name="auth103" value="auth103" id="auth103">Member Registration Listing</input></div>
<div class="col-sm-2"><input type="checkbox" name="addAuth103" value="addAuth103" id="addAuth103">Add</input></div>
<div class="col-sm-2"><input type="checkbox" name="editAuth103" value="editAuth103" id="editAuth103">Edit</input></div>
<div class="col-sm-2"><input type="checkbox" name="delAuth103" value="delAuth103" id="delAuth103">Delete</input></div>
</div>
<div class="row">
<div class="col-sm-5"><input type="checkbox" name="auth104" value="auth104" id="auth104">Geneology Listing</input></div>
<div class="col-sm-2"><input type="checkbox" name="addAuth104" value="addAuth104" id="addAuth104">Add</input></div>
<div class="col-sm-2"><input type="checkbox" name="editAuth104" value="editAuth104" id="editAuth104">Edit</input></div>
<div class="col-sm-2"><input type="checkbox" name="delAuth104" value="delAuth104" id="delAuth104">Delete</input></div>
</div>
<div class="row">
<div class="col-sm-5"><input type="checkbox" name="auth105" value="auth105" id="auth105">Member Rank Report</input></div>
<div class="col-sm-2"><input type="checkbox" name="addAuth105" value="addAuth105" id="addAuth105">Add</input></div>
<div class="col-sm-2"><input type="checkbox" name="editAuth105" value="editAuth105" id="editAuth105">Edit</input></div>
<div class="col-sm-2"><input type="checkbox" name="delAuth105" value="delAuth105" id="delAuth105">Delete</input></div>
</div>
You can assign some class to your checkbox. Then use the .each() method of jquery this way.
$(".someclass").each(function(){
if($(this).is(':checked'))
{
// Disable other checkbox in row
}
else
{
//don't disable checkbox
}
})
This will loop through all the checkbox with the assigned class and you can easily separate the checkbox of left row with class.
Though you will have to find a way, how to target other checkbox at right side in the same row.
One way you can do this is to to use each row. Then from there select the first div and get it's input. That can be used for the change event, which then you can disable all but the first checkbox:
$('.row').each(function(){
var self = this;
$(this).find('div:first input').change(function(){
// disables all but the first input in the div rows
if(this.checked) $(self).find('div:gt(0) input').attr("disabled", true);
else $(self).find('div:gt(0) input').attr("disabled", false);
});
});
Demo
This single line of code does the trick, in a change event:
$('.col-sm-5').on('change', function(){
$(this).nextAll('.col-sm-2').children('input').prop('disabled',
$(this).children('input').prop('checked'));
});
I'll break it down:
$('.col-sm-5').on('change', ...
Whenever an element with the col-sm-5 class (or one of its children) changes...
$(this).nextAll('.col-sm-2') ...
Get all the following siblings of this (the element that changed) which have the class col-sm-2 ...
.children('input') ...
Get the input elements that are children of the above...
.prop('disabled', ...
The disabled property will be set to either true or false ...
$(this).children('input') ...
Get the input box that is contained in the div with the class col-sm-5 that just changed ...
.prop('checked') ...
Find out if it's checked or not. So,
$(this).children('input').prop('checked')
evaluates to either true or false, and we're plugging it into this:
.prop('disabled', [true or false])
So, if the first checkbox is checked, the next three are disabled, and if it isn't, they aren't.

Bootstrap collapse with wrong behavior

My problem is that I have 2 blocks in modal and when I click on .emailInbound checkbox it toggle .in-serv-container open, but when I click on .accordion-heading to open comment part it makes .in-serv-container collapse.
What can be a reason?
HTML:
<label class="checkbox">
<input class="emailInbound" type="checkbox" onclick="toggleInServ(this)">Использовать Email для регистрации обращений
</label>
<div id='in-serv-container'>
<div><strong>Настройка входящей почты</strong></div>
<div>
<input class="emailOutserver" type="text" placeholder="Сервер входящей почты">
<input class="emailOutserverPort" type="text" placeholder="Порт">
</div>
<div>
<select class="emailOutProtocol half" style="width: 49%!important;">
<option value='usual'>Обычный</option>
<option value='ssl'>SSL</option>
</select>
<input class="emailInFolder half" type="text" placeholder="Папка входящей почты">
</div>
<div class="modal-body-container">
<input type="text" placeholder="Опции">
</div>
<button class="btn btn-link">Проверить подключение</button>
<hr>
</div>
<div class="accordion" id="comment-wrapper">
<div class="accordion-heading" data-toggle='collapse' data-target='#emailComment' onclick='toggleChevron(this)'>
<strong>Комментарий</strong> <i class='icon-chevron-right'></i>
</div>
<div id="emailComment" class="collapse" data-parent="#comment-wrapper">
<textarea class="emailComment"></textarea>
</div>
</div>
JS:
function toggleInServ(box){
var checked = $(box).prop('checked');
if(checked){
$('#in-serv-container').css('height', '170px');
}else{
$('#in-serv-container').css('height', '0px');
}
}
function toggleChevron(o){
var icon = $(o).children('[class*=icon]');
if(icon.hasClass('icon-chevron-right')){
icon.removeClass('icon-chevron-right');
icon.addClass('icon-chevron-down');
}else{
icon.removeClass('icon-chevron-down');
icon.addClass('icon-chevron-right');
}
}
If I'm in the right track at this, you want each dropdown to stay on opened if the checkbox is ticked? What ever is the case here, please provide us with your CSS-styling as well. Would be best if you'd give us JSFiddle of your case.
Changing just the
height
attribute of your CSS seems like a bad idea. Instead of that, you could try using
display: block;
and
display: none;
So it would really be a hidden field before it gets selected. Not the answer to the question itself, but just something to note.
It was because of 'bubbling'. I added e.stopPropoganation() and it help.

How to change the text of a <label> which is hidden

I want to change the text of a label whose parent has its display hidden. I am not able to access the label because of its parents visibility.
I would like to know is there a way to change the text of this label without the changing the visibility of the parent.
I tried changing the visibility of the label and changing the text and hiding it back, did not work.
$(document).ready(function(){
$("#394").find(".name").children("label").text("Home");
});
<div class="sample1" style="display: none;">
<div id="394">
<div class="name">
<label>house.jpg</label>
</div>
</div>
</div>
Any suggestions/ideas?
Answer:
First, Thank you all for the response.
I fixed the issue.
This is the change I made and it worked.
$(document).ready(function(){
$(".sample1").find(".name").children("label").text("Home");
});
<div class="sample1" style="display: block;">
<div style="display: none;" id="398">
<div class="name">
<label>Sample</label>
</div>
</div>
</div>
Sample
(Updated) http://jsfiddle.net/SXLnt/1/
(Old) http://jsfiddle.net/SXLnt/
Solution
$("#394 label").text("new_house.jpg");
$(".sample1").show(); // show hidden result
Sample HTML
<form id="parent_form" style="display: none; visibility: hidden;">
<label for="male" id="lb_male">Male</label>
<input type="radio" name="sex" id="male" />
<br />
<label for="female" id="lb_female">Female</label>
<input type="radio" name="sex" id="female" />
</form>
Sample JS (jQuery)
$("#lb_male").text("Man"); // Change text 1
$("#lb_female").text("Woman"); // Change text 2
//$("#parent_form").show(); // Show parent
Sample DOM result
IF the label's ID is lblSomething, you could do it in JQuery as so ...
$("lblSomething").val("Changed value")
Hope it helps.
If what you posted is your full code, it looks like you are missing a closing tag on your outer div. Try this:
<div class="sample1" style="display: none;">
<div id="394">
<div class="name">
<label>house.jpg</label>
</div>
</div>
</div>

Categories