Scoping issue when adding multiple instances of views using ng-repeat - javascript

I'm hitting a scoping issue when using the ng-repeat functionality of AngularJS.
please see the plnkr
I have an array of objects 'boxCollection' and a list of items 'itemCollection' which I display in a drop down.
$scope.boxCollection = [];
$scope.itemCollection =
[
{name: 'item1'},
{name: 'item2'},
{name: 'item3'}
];
Now I have my view as
<script type="text/ng-template" id="addBox.html">
<div class="box-controls">
<span class="glyphicon glyphicon-plus pull-left" ng-click="addBox()"></span>
<span class="glyphicon glyphicon-minus pull-left" ng-class="{disable_div:boxCollection.length < 2} " ng-click="removeBox($index)"></span>
</div>
<div class="box-container">
<div class="box-details">
<div class="boxItem">
<form class="form-horizontal">
<div class="form-group">
<label class="control-label col-md-3">Item</label>
<div class="col-md-8">
<select class="form-control" ng-options="item.name for item in itemCollection" ng-model="boxCollection[$index].item" ng-disabled="false">
<option value=""> None </option>
</select>
</div>
</div>
<div class=" form-group ">
<label class="control-label col-md-3">Item Desc</label>
<div class="col-md-8">
<input type="text " class="form-control " ng-model="boxCollection[$index].item.desc ">
</div>
</div>
</form>
</div>
</div>
<div class="clearfix "></div>
</div>
</script>
The view is wrapped in a script tag with an id and is called with an ng-repeat.
I have one function to add a box element into my view 'addBox()'. It generates one entry in 'boxCollection' array and another entry in 'boxTmplList' array. 'boxTmplList' is responsible for showing the views.
Now if you select let's say 'item1' from the drop down in box1 and add a value in the input field, add another box in the view using the '+' button and select 'item1' again in the another instance. It displays the value of input field 1 in the input field 2.
enter image description here
On further analysis I found that Angular tracks the objects with similar 'item' name using the same $hashkey.
I'm using a workaround by adding another property to the object 'boxCollection[$index].itemDesc' instead of 'boxCollection[$index].item.desc' and then later on modify the object using another function, but I feel that's not the most efficient way.
Any insight on this would be greatly appreciated.

You need to change ng-model="boxCollection[$index].item" to ng-model="boxCollection[$index].item.name" , like as-
<select class="form-control" ng-options="item.name for item in itemCollection" ng-model="boxCollection[$index].item.name" ng-disabled="false">

Working Plnkr
Change ng-model="boxCollection[$index].item.desc" to ng-model="itemCollection[$index].name".
<div class=" form-group ">
<label class="control-label col-md-3">Item Desc</label>
<div class="col-md-8">
<input type="text " class="form-control " ng-model="itemCollection[$index].name">
</div>
</div>

Related

Fill several times content of same form fields and write it into several lines of a database

I have built a form. I put a button inside this form called "Add a book". When a user clicks two fields appear : "bookname" and "bookdate" :
<div class="form-group col-md-3">
<a class="btn btn-success" onclick="add()" href="#">
<i class="glyphicon glyphicon-plus icon-white"></i>Add a book
</a>
</div>
<div id="wrapper">
<!-- champs du formulaire -->
<div class="form-group col-md-12" id="add" style="display:none;">
<!-- Bookname -->
<div class="form-row">
<div class="form-group col-md-3">
<label for="exampleInputPassword1">Name of book</label>
<input type="text" class="form-control" id="bookname" name="bookname">
</div>
</div>
<!-- Bookdate -->
<div class="form-row">
<div class="form-group col-md-3">
<label for="exampleInputPassword1">Date of book</label>
<input type="text" class="form-control" id="bookdate" name="bookdate">
</div>
</div>
</div>
</div>
When there is only one book, there are no problem to validate the form and write the "bookname" and "bookdate" to the project database. It's very common.
My question is : for example if a user clicks 3 times on the "add book" button and fills 3 times the "bookname" and "bookdate" fields , how could I do in the code to save all that into three different lines in the database ?
That is to say :
bookname bookdate
name1 date1
name2 date2
name3 date3
I don't see how i could do ?
Any help would be very appreciated.
Thank you !
You need to change the name attribute on your bookname and bookdate inputs to array notation i.e.
<input type="text" class="form-control" id="bookname" name="bookname[]">
<input type="text" class="form-control" id="bookdate" name="bookdate[]">
Then, in your PHP code, you will find that $_POST['bookname'] and $_POST['bookdate'] are now arrays of values, so you can iterate through them e.g.
foreach ($_POST['bookname'] as $k => $bookname) {
$bookdate = $_POST['bookdate'][$k];
// write bookname and bookdate to database
...
}

related UI not update in v-for

I have an array in my data object and it will push as many time user wants to add data to it, and it is rendering with v-for perfectly.
The problem is related UI part didn't update, see the following picture :
this is init of the page and there is an empty object in array
when I press add button panel-body would not update with new v-for generated elements:
thanks
EDIT:
When I write the code in pure pure html(copy it in code), it look like this, that is a target UI.
EDIT 2:
data :
data() {
return {
payment: {
type: "check",
checks: [{}]
}
}
}
ui :
<div v-for="(check,index) in payment.checks">
<br>
<h5>
index of array ->
{{index}}
</h5>
<div class="form-group">
<label class="col-md-3 control-label">
something
<label style="color:red">*</label>
</label>
<div class="col-md-9">
<input type="text" class="form-control" v-model="check.amount" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">
someting else
<label style="color:red">*</label>
</label>
<div class="col-md-9">
<input type="text" class="form-control" v-model="check.dadada" />
</div>
</div>
<div class="col-lg-8" style="padding-top: 3%;">
<button v-on:click="payment.checks.push({})" class="btn btn-success" style="margin-right: 7%;">
add
</button>
</div>
</div>

How to retrieve value from <select> and put it in hidden JSTL

i have a rather dumb issue but still, can not figure the way around it...The concept is to have a select value which prompts the user to select a subject. Upon selection i need to store that subject id in every form that i am using below in so i can retrieve that subject, and i dont want to use different select for every single form that i need. here is the code below:
<div class="input-field col s12">
<select>
<c:forEach var="subjectItem" items="${subjectList }">
<option value="${subjectItem.id }">${subjectItem.subjectName }</option>
</c:forEach>
</select> <label>For subject</label>
</div>
......
.....
<form method="POST" action="subject-add-school-deadline"
id="deadlineSchoolForm">
----! Here is should retrieve that data from select !-------
<div class="row">
<div class="input-field col s6">
<input id="schoolD_title" type="text" class="validate"
name="title""> <label
for="schoolD_title">Title</label>
</div>
</div>
<div class="row">
<div class="input-field col s12 l12 ">
<textarea id="schoolD_desc" name="description"
class="materialize-textarea validate" form="deadlineSchoolForm"></textarea>
<label for="schoolD_desc">Description</label>
</div>
</div>
<div class="row">
<label class="col s2">Deadline date</label> <input type="date"
class="datepicker col s4" name="date">
</div>
<div class="row right-align">
<button class="waves-effect waves-teal btn-flat" type="submit"
name="action" >
Add <i class="material-icons right">input</i>
</button>
</div>
</form>
----MORE FORMS BELOW ------
.....
.....
Note that i do not need something like
<select form="form1>
because i need that select value for multiple forms. Any help would be greatly appreciated. Thanks!!
I used jQuery to set the value in all inputs named title. Would this solve your problem?
JS Fiddle
The important part:
<script type="application/javascript">
$("select#foo").change(function() {
$("input[name='title']").val($("select#foo").val());
});
</script>

JQuery .addClass and .removeClass not working on Chrome or Safari

I'm trying to show and hide divs using a button. This code works just fine in Firefox and IE, but for some reason it's not working in Chrome or Safari. The site is using Bootstrap.
function newAdd(addId, rowId) {
var add = "#" + addId.id;
var row = "#" + rowId.id;
var nextNum = Number(add.charAt(4));
nextNum++;
var next = "#add" + nextNum;
$(add).addClass("dontShow");
$(next).removeClass("dontShow");
$(row).removeClass("dontShow");
}
.dontShow {
display: none;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row" id="row1">
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label for="000-000">Item Name:</label>
<br />
<input type="text" class="form-control" value="">
</div>
</div>
</div>
<div class="row" id="add1">
<div class="col-sm-1 col-md-1"> </div>
<div class="col-sm-2 col-md-2">
<a onclick="newAdd(add1,row2)">
<button class="btn" style="text-decoration: none; color: #ffffff;" id="add1" type="button">Add another item?</button>
</a>
</div>
<div class="col-sm-9 col-md-9"> </div>
</div>
<div class="row" id="row2">
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label for="000-000">Item Name:</label>
<br />
<input type="text" class="form-control" value="">
</div>
</div>
</div>
<div class="row" id="add2">
<div class="col-sm-1 col-md-1"> </div>
<div class="col-sm-2 col-md-2">
<a onclick="newAdd(add1,row2)">
<button class="btn" style="text-decoration: none; color: #ffffff;" id="add1" type="button">Add another item?</button>
</a>
</div>
<div class="col-sm-9 col-md-9"> </div>
</div>
<div class="row" id="row3">
<div class="col-sm-12 col-md-12">
<div class="form-group">
<label for="000-000">Item Name:</label>
<br />
<input type="text" class="form-control" value="">
</div>
</div>
</div>
So what should happen is, the user sees the first row and first button and everything else is hidden. They fill out the first row, then click on the button. When clicked, the button goes away and the next row and next button appear showing two rows with one add button at the bottom. If they click it again, then the last row should appear and the add button goes away completely.
There are 2 solutions possible to achieve the result.
Solution 1
There are 2 updates that need to be done in your code
In HTML
There should be quotes for stirngs like newAdd('add1','row2')
In JS, no need for addId.id
var add = "#" + addId;
Solution 2
No html update. Only in JS, update
var add = "#" + addId.id;
to
var add = "#" + addId[0].id;
Solution 1 - You are passing the id of the element and accessing it in javascript.
Solution 2 - You are passing the HTML Object Collection and then accessing the element and its id property.
Now which solution to go for?
In case you only need Id, you can go for solution 1, as it makes no sense to pass the complete collection just to extract the id which can otherwise be send with the same parameters with just quotes around them.
However, if you need to get some other properties of the element, then go for solution 2.
The reason why it doesn't work in Chrome or Safari is that add1, which you are passing to the function, i.e.
addNew(add1, row1);
does not refer to a single element, but to an element collection:
Why? Because you have multiple elements with the same ID. IDs have to be unique!
Firefox on the other hand simply takes the first element with that ID (which is what I would have expected).
There are a couple of ways to solve this, one of them shown in the other answer, but you should definitely ensure that you are only using unique IDs. I highly recommend to read up on binding event handlers with jQuery: http://learn.jquery.com/events/event-basics/

Bootstrap styling of glyph as a button

I'm building a page with a series of inputs. One of them is a select list of email addresses. I'm including a Plus glyph at the right end of the list as a button to invoke some javascript that will add additional select lists for more recipients.
I've spent quite a bit of time trying to do this without the results I was hoping for. The best I can do is this code example. If you click directly on the plus, you get the result. However, I wish that the entire square surrounding the glyph was clickable instead - not unlike a button. Any suggestions? Thank you!
<div class="form-group">
<label for='the_user_email' class='col-sm-2 control-label' style='padding-right: 0px;'>Requested By</label>
<div class='col-sm-6'>
<div class="input-group" id="add_emails_event">
<select class='form-control' name='the_user_email' id='the_user_email'>
<option value='user1#domain.com'>user1#domain.com
<option value='user2#domain.com'>user2#domain.com
</select>
<span class="input-group-addon"><a onclick="add_email();"><span class="glyphicon glyphicon-plus"></span></a></span>
</div>
</div>
</div>
You can solve this by using a button.
<div class="form-group">
<label for='the_user_email' class='col-sm-2 control-label' style='padding-right: 0px;'>Requested By</label>
<div class='col-sm-6'>
<div class="input-group" id="add_emails_event">
<select class='form-control' name='the_user_email' id='the_user_email'>
<option value='user1#domain.com'>user1#domain.com
<option value='user2#domain.com'>user2#domain.com
</select>
<span class="input-group-btn"><button onclick="add_email();" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span></button></span>
</div>
</div>
</div>

Categories