Ng-repeat and auto complete selection with modal window in Angular - javascript

I'm doing an application in Angular. It is a Table one row that contain 2 column. Each column contain one select. They are empty. When the user press a button, a modal window shows up and display a grid with all the items (from json) of the first select. When the user click on one rows and press "Confirm", modal window closes filling the first select. In the meanwhile, the second select fill with the subarray of selected item.
In a few words, there are 2 select: you choose the option on the first (by a modal window) and then you choose the item of its subarray in the second select.
Then, the user can add new rows, repeating the select.
I've tried two ways to do this, and they half work. In the FIRST CODE
you can see that, after clicked on modal window, the first select fill it self (even if it is not the first , I don't know why..). And it doesn't not iterate well, because when you choose a item in new line, it modify all the other choises, and I want to prevent this.
<select ng-model="selectedProduct" ng-options="a as a.nome for a in items" ng-change="selectLot(select1)">
<option value="">-- Select Product --</option>
</select>
<select ng-model="selectedLot" ng-options="a as a.value for a in selectedProduct.lots" ng-change="lotSelect(select2)">
<option value="">-- Select Lot --</option>
</select>
The SECOND CODE works better. It iterate well. It change automatically the second item's selection well. But when I press on the modal window, the first selection doesn't automatically fill with the choosen item.
Can you help me? I can't find a solution..... Thank you so much in advice!

The core of the issue is that if you want to have a form that edits elements in an array, you need to have separate models for each of the rows in the array. You can do this by making "selectedProduct" and "selectedLot" into objects that map the array index to the selected value for that row.
I made an updated plunker with a working example, but without looking at it here is a rundown of the changes you would need to make. You need to change your models so they reference something using the array index of the row, and also pass that index into functions that modify the row:
<button class="btn btn-default" ng-click="open($index)">OPEN!!</button>
<select ng-model="selectedProducts[$index]" ng-options="a as a.nome for a in items" ng-change="selectLot(select1, $index)">
<option value="">-- Select Product --</option>
</select>
<select ng-model="selectedLots[$index]" ng-options="a as a.value for a in selectedProducts[$index].lots" ng-change="lotSelect(select2, $index)">
<option value="">-- Select Lot --</option>
</select>
You also want to update the functions in your controller to work with the array indexes:
$scope.selectLot = function(data, index){
$scope.Subarray = [];
for(i=0; i<$scope.items.length; i++){
if(data == $scope.items[i].id){
$scope.Subarray[$index] = $scope.items[i].lots;
$scope.selectedProducts[$index] = $scope.items[i];
break;
}
}
console.log($scope.Subarray);
}
$scope.lotSelect = function(id, $index) {
for(i=0; i<$scope.Subarray[$index].length; i++){
if(id == $scope.Subarray[$index][i].id){
$scope.selectedLots[$index] = $scope.Subarray[$index][i];
break;
}
}
}
And the modal:
$scope.open = function ($index) {
// ...
modalInstance.result.then(function (selectedItem) {
$scope.selectedProducts[$index] = selectedItem;
}, function () {
$log.info('Finestra selezione prodotto chiusa alle ore: ' + new Date());
});

You probably shouldn't be using a SELECT if you are allowing the choice to happen in a modal popup. All you want to do is show the selected item which you can easily do in a number of different ways. Additionally in the first example prodIsChanged(), which is what sets the subarray, is never called. An easier solution may be something like this:
<div>{{mainProduct}}</div>
<select ng-options="a as a.value for a in selectedProduct"></select>
var myApp = myApp.controller('Cntrl', function ($scope,$watch) {
$scope.mainProduct = '';
$scope.selecedProduct = '';
$watch('mainProduct',function(old,new) {
$scope.selectedProduct = ??? // The mainProduct has changed so set the list of sub products as necessary
};
}

Related

select drop down option based on associated text

I have a drop down with a value and associated text as such:
echo '<option value="'.$row['company_id'].'">'.$row['company_name'].'</option>';
Eventually, the output of the selected option is put into a table, row by row. By each row, there is an edit button to edit that particular row and select a new drop down option. I'm trying to use JavaScript to select the text and when they hit the edit button, the option that is currently set will be the default choice.
So for instance, if the row says the company_name is: ABC Company, when they hit the edit button, the drop down will populate with that option. Since the value and text are different, I need to choose the drop down option based on text. I have tried these 2 options so far with no luck.
To get the row text:
var d = document.getElementById("itable").rows[id].cells[3].innerText;
I have tried the following to pass back the text of the row, and to select the drop down by text.
document.querySelector('#editinsurancepolicymodal select[name=editicompanydropdown]').value = d;
This option just populates the drop down, but no choice is selected.
document.querySelector('#editinsurancepolicymodal').find('option[text="InsuranceB"]').val;
This option selects the first option in the drop down, but doesn't change based on what the 'text' is.
Thank you for your help in advance.
One way will be to iterate over the option elements, selecting the one that has the same text as the text from the row, and un-selecting all the others. This is illustrated in the snippet below (I have inserted a 3 second timeout, so that you can see that the initially selected option (Two) is changed to the option with the text "Three" from the JavaScript code.
window.setTimeout(function () {
var sampleWord = "Three";
var options = document.querySelectorAll("option");
for (var i = 0; i < options.length; i++) {
var option = options[i];
if (option.innerText === sampleWord) {
option.selected = true;
} else {
option.selected = false;
}
}
}, 3000);
<select id="selector">
<option id="option-1" value="1">One</option>
<option id="option-2" value="2" selected>Two</option>
<option id="option-3" value="3">Three</option>
<option id="option-4" value="4">Four</option>
</select>
Alternately, you could store the id for the company as a data-attr attribute on the row. For example (in PHP):
echo "<td data-attr-company-id=".$row['company_id'].">".$row['company_name']."</td>"
Then, you can read the attribute from the table row, and query for the option that has the same value as your attribute value.
var options = document.querySelectorAll("option");
This will select all options from the page. If you want to get the options for a specific drop down, use the following:
var options = document.querySelector('#specificform select[name=specific_drop_down_in_the_specific_form]');
To select the option based on the text and not the value, use this loop:
for (var i=0; i<options.length; i++){
var option = options[i];
if (option.innerText === d){
option.selected = true;
}
}

How to return the length and value of a selection in a datalist?

I would like to fabricate some code, that tracks the amount of unfiltered options in a datalist. So how could I keep track of this?
Secondly when there is only one option left in the list I want to access the value of this option.
Here is a link to the w3c spec: https://www.w3.org/TR/html5/forms.html#the-datalist-element
Note: I want to use the datalist, so I don't want to create my own filter on the datalist and get the values from there.
I came up with this code so far:
Fiddle: https://jsfiddle.net/6usf7j9g/
html
<h3>Anything you'd like?</h3>
<input id="your-favourite" list="choices"/>
<datalist id="choices">
<option value="Laphroaig"></option>
<option value="Jameson"></option>
<option value="Talisker"></option>
<option value="Oban"></option>
<option value="Dalwhinnie"></option>
<option value="Glennfidich"></option>
<option value="Glenlivet"></option>
</datalist>
jQuery/js
var selectedChoices = null; //in this variable I need to know how many items are left in the list after filtering. If you type "Glen" it should be two, if you type "Glenn", "J", etc. it should give a value of 1. It only needs to work on google chrome.
$("#your-favourite").on("keyup", function(){
selectedChoices = null; //PART OF THE ISSUE: Should change the value of the variable here, depending on the options that are showing.
if(selectedChoices === 1){
let finalOption = "unknown"; //PART OF THE ISSUE: Should load the value of the remaining option
// validate success
alert("There is only one value left in the list! It is called: " + finalOption);
selectedChoices = null; // reset value to 0.
}
// log the datalist and input elements, it might have some info that helps finding a solution.
console.log($("#your-favourite"));
console.log($("#choices"));
}); // end on keyup

How do I get ng-select to update when scope is changed?

I have a table above a form, that when a row is selected it populates a form with data. That form has a select element. Upon the first row in the table being selected, the data populates correctly and the correct selected option is shown. On the second and subsequent selection the correct selected option is not shown. In chrome dev tools I can see the values update properly, but it is not visually shown.
What am I missing? How do I get that correct option to be visually shown?
<select name="updateCategory" ng-model="selectedPermission.permission.category_id">
<option value="{{cat.id}}" ng-selected="cat.selected" ng-repeat="cat in selectedPermission.permission_categories">
{{cat.name}}
</option>
</select>
Here is function in controller that is updating the scope.
$rootScope.$watch('toolBarSelectedValue',function(){
if($rootScope.toolBarSelectedValue >0){
Permissions.getItem($rootScope.toolBarSelectedValue).then(function(res){
var pc = res.data.permission_categories;
var p = res.data.permission;
angular.forEach(pc,function(v,k){
if(v.id == p.category_id){
pc[k].selected = true;
}else{
pc[k].selected = false;
}
});
$scope.selectedPermission = {"permission":p,"permission_categories":pc};
$scope.$apply();
});
}else if($rootScope.toolBarSelectedValue == 0 || $rootScope.toolBarSelectedValue == null){
$scope.selectedPermission = {};
}
});
I would use ng-options as opposed to <option...></option> you can then relate your selection to your ng-model easily. See docs for more info.
Something like:
<select name="updateCategory" ng-model="cat" ng-options="cat.id as cat.name for cat in selectedPermission.permission_categories">
</select>
bear in mind I am not sure of you data structure, but this should get you on your way.

AngularJS: ngRepeat for select on change ngOptions-list

I have an angularjs app, which has a select filled with options from an arry, using ngOptions. Every time the user clicks the button to add one, the ngRepeat directive generates a new select at the bottom.
I want to make sure that the user cannot select duplicate values.
So if my list contains 3 items: Item1, Item2 and Item3, and the user selects Item3 and then presses the button, the last generated select list should contain only items 'Item1' and 'Item2'.
If the user would then select 'Item1' and presses the button, the user should see the next select be generated with only the 'Item2' option.
So generally, in the case above, the generated HTML should be something like this:
<div data-ng-repeat="item in selectedOptions">
<select>
<option value="1">Item1</option>
<option value="2">Item2</option>
<option value="3">Item3</option>
</select>
<select>
<option value="1">Item1</option>
<option value="2">Item2</option>
</select>
<select>
<option value="2">Item2</option>
</select>
</div>
Keep in mind: the user will keep seeing all THREE of the selects, once with every option available, once with just two options available, and once with just one option available.
I've been thinking of a lot of ways to make this work, but so far I haven't had any luck. Does anyone know of a pattern I can use in angular to achieve this behavior?
This is something that I've tried so far.
<div data-ng-repeat="function in item.Functions">
<select data-ng-model="function.Id" data-ng-options="j.Id as j.Name for j in getCorrectFunctions(functionsList)">
<option selected="selected" value="">---</option>
</select>
<a data-ng-click="addFunction()">
<i class="fa fa-plus fa-plus-lower"></i>
</a>
</div>
and in my directive code I have following function:
function getCorrectFunctions(functionList) {
var item = scope.item;
var list = functionList.slice();
//excluded for brevity: this was a loop which would remove every item that wasn't available anymore
return list;
}
I thought this would be executed once for every item in the list, but that does not seem to be case.
I don't think applying a filter would be any different, would it?
Here's one take on this. This does not have support for dynamically adding new functions, but however it does prevent user from selecting any given item twice.
See Plunker for working example and more details.
First the Angular setup part. Here I've defined a mock array of function objects ($scope.functions) and array for user made selections ($scope.selected)
var app = angular.module('app', []);
app.controller('SelectCtrl', function ($scope) {
$scope.functions = [
{id: 1, name: 'First'},
{id: 2, name: 'Second'},
{id: 3, name: 'Third'},
];
$scope.selected = [];
$scope.selectedFilter = function (selectNumber) {
// snipped for now
};
});
In html, showing only one select, but similar approach used for all 3 selects: set the selected value to the selected array in given index (0 for the case shown below), and use selectedFilter to filter functions with same index value.
<select ng-options="j.id as j.name for j in functions | filter:selectedFilter(0)" ng-model="selected[0]">
<option value="" selected="selected">---</option>
</select>
Then finally the filtering function. It returns true for all unselected functions and for the selected function of the given select.
$scope.selectedFilter = function (selectNumber) {
return function (func) {
if ($scope.selected.length === 0) {
return true;
} else {
var unselectedFunctions = _.filter($scope.functions, function (fn) {
return _.findIndex($scope.selected, function (sel) {
return fn.id === sel;
}) === -1;
});
var selectedForCurrentId = $scope.selected[selectNumber];
var selectedForCurrent = _.find($scope.functions, {id: selectedForCurrentId});
return func === selectedForCurrent || _.findIndex(unselectedFunctions, {id: func.id}) > -1;
}
};
};
Here I've used Lodash for some nice helper functions. Not affiliated with Lodash in any way, but I really suggest you to take a look at it, or any other similar library.
Hopefully this helps you to get things moving on!

how to Target an option from pull down with js to apply more code

a friend asked me to help him with a form, a client of his wants to make a form a bit more dynamic...my javascript is minimal at best since i just started learning.
He asked me something along the lines of " how can i make a form show another pull down ONLY WHEN a certain option is selected "
in the example he gave me, by default when page loads,he has a pull down menu which has 2 options, MANHATTAN and option two is BROOKLYN.
If Manhattan is chose, that reveals another pull down with zips for manhattan, if Brooklyn is chosen the same for BK.
in sample html, something along the lines like this:
<div>
<form>
<select name="boro" id="boro">
<option value="manhattan" id="manh">Manhattan</option>
<option value="brooklyn" id="brook">Brooklyn</option>
</select>
</form>
<br/>
<div id="empty2fill"></div><!-- for showing chosen results -->
</div>
i want to target/capture the option chosen by the user above on the pull down menu, to then activate this function(below).
according to his request what i guess id do is,(as a newbie), then as far as the .js goes (pseudo code):
<script type="text/javascript">
function valBoro (){
if( brook is chosen){ document.getElementById('empty2fill').innerHTML=" new dropdown code here")
}
}
</script>
aside from not knowing, my main problem is i dont know how to target the option chosen in the menu to thereafter, apply the function (which will be written later)
any ideas, tips etc are greately appreciated.
thanks in advance
Another option is to create the two dropdown lists and set the style display to "none". Then you can catch the onChange event and set display to "" based on the value of the select element.
function showZip() {
var boro = document.getElementById("boro");
if (boro.value == "manhattan") {
var zipManhattan = document.getElementById("zipManhattan");
zipManhattan.style.display = "";
}
}
And in the html
<div>
<select name="boro" id="boro" onchange="javascript:showZip();">
<option value="manhattan" id="manh">Manhattan</option>
<option value="brooklyn" id="brook">Brooklyn</option>
</select>
<br/>
<select name="zipManhattan" id="zipManhattan" style="display:none;">
<option value="zip1" id="zip1">1111</option>
<option value="zip2" id="zip2">2222</option>
</select>
<div id="empty2fill"></div><!-- for showing chosen results -->
</div>
Here is a link to a jsfiddle showing example code.
http://jsfiddle.net/WKqth/
Example markup:
<div>
<form>
<select name="boro" id="boro">
<option value="" id="none">Select a boro.</option>
<option value="manhattan" id="manh">Manhattan</option>
<option value="brooklyn" id="brook">Brooklyn</option>
</select>
</form>
<br/>
<div id="empty2fill"></div><!-- for showing chosen results -->
</div>
Example js
// include this js below the form in the body, or wrap it in a function and assign that to window.onload, or use a library that provides onDomReady (in jQuery, $(document).ready(function () ... });
var selectElement = document.getElementById('boro');
var showBoroSelect = function () {
// find the selected element
var selectedOption = selectElement.options[selectElement.selectedIndex].id,
// find the element that will contain the new drop down
containerElement = document.getElementById('empty2fill'),
// define the html for the manhattan drop down
manhSelectInnerHTML = '<select name="secondary"><option value="derp">manh derp?</option><option value="herp!">manh herp!</option></select>',
// define the html for the brooklyn drown down
brookSelectInnerHTML = '<select name="secondary"><option value="derp">brook derp?</option><option value="herp!">brook herp!</option></select>',
newInnerHTML;
// determine which html to use based on the selection
if (selectedOption === 'manh') {
newInnerHTML = manhSelectInnerHTML;
} else if (selectedOption === 'brook') {
newInnerHTML = brookSelectInnerHTML;
} else {
// no boro was selected, hide the menu
newInnerHTML = '';
}
// set the container to the new innerHTML
containerElement.innerHTML = newInnerHTML;
};
// when the boro select changes, show the new menu
selectElement.onchange = function () {
showBoroSelect();
};
// if you select a boro and reload the page, the boro may already be selected (for example, firefox might do this)
// this will set the boro menu initially before the user changes it
showBoroSelect();
You want to handle the change event of your "boro" select element.
I've put a plain-JS example solution on jsfiddle at http://jsfiddle.net/FHArd/1/
This creates three select lists - one is your "boro" and the other two are the zip code lists, but they are hidden via CSS until a selection is made.
The change event handler simply adds and/or removes classes from the zip code select elements; the CSS hides or shows the lists based on the class "active" that is attached to the zip code select list.
Note - being there in jsfiddle the way you start things up is a little different than normal. You'd really run your setup function at the onload or ondomready event.
This should do it.
<select name="boro" id="boro" onchange="valBoro(this)">
<option value="manhattan" id="manh">Manhattan</option>
<option value="brooklyn" id="brook">Brooklyn</option>
</select>
<script type="text/javascript">
function valBoro(dropDown) {
if (dropDown.options.[dropDown.selectedIndex].value.equals("manhattan")) document.getElementById('empty2fill').innerHTML = "newHTMLCode";
//change "manhattan" to whatever option you want to use
}
</script>

Categories