Nested options using angular - html

$scope.senders = {}
$scope.senders.list = [{name: NYC, supportedSendingMethods: ['Send by mail', 'Send by sms', 'c']}, {name: GEN, supportedSendingMethods: ['Send by mail','Send by sms','c']}];
$scope.senders.selected = $scope.senders[0];
$scope.senders.selectedSending = $scope.senders[0].supportedSendingMethods[0];
First select:
<select ng-model="senders.selected" ng-options="sender.name for sender in senders">
</select>
//This one works as expected
Supported sending method:
<select ng-model="senders.selectedSending" ng-options="supp.supportedSendingMethods for supp in senders | filter:{name:senders.selected.name} ">
</select>
The last select shows all supported sending methods for the selected sender. The problem is that the options in the second select are arraylists themselves.
How can I go one level deeper (with filters) and show
1) show the supportedSendingMethods
2) of the selected sender?

As you already have selected sender stored into senders.selected variable then why just not use it? This is the best option I think:
ng-options="supp for supp in senders.selected.supportedSendingMethods"
Just to answer the original question I may propose two ways achieve what you need with filtering expression. One way is just access first item of the filtered collection - angular.js supports such expressions:
ng-options="supp for supp in (senders | filter:{name:senders.selected.name})[0].supportedSendingMethods "
Another option is to define separate filter for that - it will look better a bit:
ng-options="supp for supp in senders | filter:{name:senders.selected.name} | getFirst:'supportedSendingMethods'"
You may see all ways in actions here - http://jsfiddle.net/GRaAL/WMAea/.

You can try this way without filters. Th point is to set model of senders.currentSender as list for second select:
HTML
<div ng-controller="fessCntrl">
<select ng-model="senders.currentSender"
ng-options="sender.name for sender in senders.list"></select>
<select ng-model="supp"
ng-options="supp for supp in senders.currentSender.supportedSendingMethods"
ng-init="supp=senders.currentSender.supportedSendingMethods[0]"
></select>
</div>
JS
var fessmodule = angular.module('myModule', []);
fessmodule.controller('fessCntrl', function ($scope) {
$scope.senders = {};
$scope.senders.list = [{
name: 'NYC',
supportedSendingMethods: ['Send by mail1', 'Send by sms1', 'c1']
}, {
name: 'GEN',
supportedSendingMethods: ['Send by mail2', 'Send by sms2', 'c2']
}];
$scope.senders.currentSender = $scope.senders.list[0];
$scope.supp = $scope.senders.currentSender.supportedSendingMethods[0];
});
By adding the $watch we can now select by default 1st value:
$scope.$watch(function () {
return $scope.senders.currentSender;
},
function (newValue, oldValue) {
$scope.supp = newValue.supportedSendingMethods[0];
}, true);
Demo Fiddle

Related

Selected Options doesnt display on the field but is sent correctly to backend

So i have a project in which i have to display some data from the table. Now i want to change the size of the data based on a field above the table that is actually a select input field and sends a value to the angular controller. Now this is working perfectly except for the fact that the field doesn't show the selected number of data being displayed on the field.
This is the empty field. but the data is inserted correctly. Also on debugging I found another option here on the field that is not in the html code. Here's my code for the html and the controller.
View:
<li class="manual-dropdown pull-right">
<select id="ddPageSize" ng-model="PaginationInfo.pageSizeSelected" ng-change="ChangePageSize()" aria-controls="DepartmentTable" class="form-control pull-right">
<option value="5">5</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="-1">All</option>
</select>
</li>
Controller:
$scope.PaginationInfo = {
maxSize: 5, // Limit number for pagination display number.
totalCount: 0, // Total number of items in all pages. initialize as a zero
pageIndex: 1, // Current page number. First page is 1.
pageSizeSelected: 5, // Maximum number of items per page.
}
GetData(searched);
function GetData(searched) {
//debugger
//var noOfPages = 1;
var SearchData = $scope.StatusSearch.Search;
if (SearchData == "") {
searched = false;
}
var Displaysize = $scope.PaginationInfo.pageSizeSelected;
var index = $scope.PaginationInfo.pageIndex;
if (searched == false) {
Get("/User/GetData?Size=" + Displaysize + "&index=" + index, false).then(function (d) {
//$("#").val()
//$scope.userAccount.CountryID = $("#ddCountryOptions").val();
// $scope.PaginationInfo.maxSize = d.info.maxSize;
$scope.PaginationInfo.totalCount = d.totalSize;
$scope.PaginationInfo.pageIndex = d.index;
$scope.PaginationInfo.pageSizeSelected = d.size;
//$scope.noOfPages = $scope.PaginationInfo.totalCount / $scope.PaginationInfo.pageSizeSelected;
$scope.accountlist = d.GetList;
$scope.$apply();
})
}
else {
// alert($scope.SearchData.Search);
Get("/User/SearchData?inputstring="+ SearchData, false).then(function (d) {
$scope.accountlist = d.GetList;
$scope.PaginationInfo.pageIndex = index;
$scope.PaginationInfo.pageSizeSelected = Displaysize;
$scope.PaginationInfo.totalCount = d.totalSize;
$scope.$apply();
});
}
}
explanation for the Controller: The data is loaded on page load so the GetData() function is called immediately. the default page size is set to 5 as shown and when i make a change to the field i recall the GetData() function with page size as a argument and the back end does the rest and returns a amount of data that i asked for. Also the reason there are 2 ajax calls in this function is to implement a search function. which check if the input field is empty or has a value and based on that output the data.
What i want to know is why is the page size field on my dropdown empty when i select a value.
Edit:
After a bit more research i found that the ng-Model is making a empty option with the value of the option i selected. Now the problem still remains i don't know how to display the value in the empty object. if i do select another option as selected, my ng-model value does not change. So i am still stuck with this. Also i have already give the ng-model an default value of 5 the same as my first dropdown option. so in case i tag any other option as selected, the ng-model option will remain 5 no matter how many times i change the dropdown value.
Alright i kind of solved my issue, though I am not sure if this is a good way to do it.
So what i did is simply bind the pageSizeSelected Value to the html select element by id.
$("#ddPageSize").val(d.size)
$scope.pageSizeSelected = $("#ddPageSize").val();
before $scope.$apply and it worked. Now when i select a value from the field it changes and displays the value i selected.

How to overwrite text in AngularJS using a filter

Still learning Angular however I need a quick fix for something and I can't figure it out. I have a site that gives you the USPS shipping options and need to tell the website to use my text instead of the vendor's. The vendor's says '2-Day Ship™' but I want to replace that with just 'Standard Ground'.
This is what I have for my filter:
app.filter('shipFilter',function() {
return function(string) {
if (string) {
return string.replace('2-Day Ship™', 'Standard Ground');
}
}
And in my html:
<select class="form-control" ng-change="updateShipper()" name="shipMethod"
ng-model="currentOrder.LineItems[0].ShipperName"
ng-show="user.ShipMethod.ShipperSelectionType == 'UserDropDown'"
ng-options="shipper.Name | shipFilter as (shipper.Name + ' ' + (shipper.ShippingRate.Price | currency | xlat)) for shipper in shippers"
ng-required="!currentOrder.IsMultipleShip() && user.ShipMethod != null" />
<option value=""></option></select>
It seems like it would be an easy patch however I'm running into walls and out of time.
Cheers
It's been a while but I wanted to post what I did to fix. I had to do this:
filter.js
//For changing USPS shipping option in dropdown
four51.app.filter('USPSFilter',function() {
debugger;
return function(object) {
if (object) {
return object.replace(/USPS Priority Mail 2-Day™/g, 'US Postal Ground');
}
}
});
Added this to html to display change in dropdown:
ng-options="shipper.Name as ((shipper.Name | USPSFilter) + ' ' + (shipper.ShippingRate.Price | currency | xlat)) for shipper in shippers"
Added this to my controller.js:
$scope.items = [{name: 'Ground' },{ name: 'Rush' }]
I'm on the same page at #MatthewGreen here. You have an array in your scope, so you can just modify the array in scope. However if that absolutely isn't possible I wrote a snippet that correctly changes the string name.
strs = [
"2-Day Ship™",
"Next Day"
]
var filter = function(string) {
if (string) {
return string.replace(/2-Day Ship™/g, 'Standard Ground');
}
}
console.log(strs)
strs = strs.map(filter)
console.log(strs)

How to filter or custom filter array of objects based on matching values from another object

I implemented an advance search with 15 input fields in AngularJS.
In the page load itself the result set is return from database in JSON format and i need to do the filter in client side only.
The input criteria's equivalent column is available in the result set and i need to check in its respective column only.
I am converting each column by JSON.stringify() and check with the search params like the below :
$scope.filteredData = $scope.actualData.filter(function(item) {
return JSON.stringify(item.FirstName).toLowerCase().indexOf(lowerFirstName) != -1 &&
JSON.stringify(item.LastName).toLowerCase().indexOf(lowerLastName) != -1 &&
JSON.stringify(item.EmailAddress).toLowerCase().indexOf(lowerEmailAddress) != -1 &&
JSON.stringify(item.Address1).toLowerCase().indexOf(lowerAddress1) != -1 &&
JSON.stringify(item.Address2).toLowerCase().indexOf(lowerAddress2) != -1;
...... etc // upto 15 fields
});
Since i have the 15 input fields and the actual result set contains a minimum of 50,000 records.
So converting each record's each column by JSON.stringify() and check with search params will surely cause the performance issue.
Is there any other way to achieve the filtering in client side with other approach.
I posted a sample code in Plunker with 5 input fields only : http://plnkr.co/edit/nUWZEbGvz7HG6gb91YZP
sylwester's answer is the normal way you'd filter things. Your code looks like you want to filter down to only the object that matches every input field. You code attempts to find an object where every property matches the searchParams object. At that point, I don't see what benefit there is to finding that object, because the user already created the object again! Nonetheless, here's a proper version of your code:
Live demo here.
<div ng-repeat="data in actualData | filter:searchData()">
$scope.searchData = function() {
return function(item) {
return Object.keys(item).every(function(key) {
// skip the $$hashKey property Angular adds to objects
if (key === '$$hashKey') { return true; }
var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
return item[key].toLowerCase() === $scope.searchParams[searchKey].toLowerCase();
});
};
};
You really need to limit the data coming from the server for the browser's sake and for the server's sake. It's easy to implement a LIMIT, OFFSET system. It sounds like, overall, you just need to be able to query the server for a certain record.
From your comments, it seems you definitely want Angular's built in filter filter:searchParams, and just capitalize your searchParams models to match your data. For fun, I'll include more options for finer tuning.
This one almost mimics filter:searchParams. You can change > 1 to adjust when the partial matching kicks in, or have it return true only when both items are strictly equal === to disable partial matching. The difference here is that all items are hidden until matched, whereas filter:searchParams will show all items and then remove what doesn't match.
Live demo here.
$scope.searchData = function() {
return function(item) {
return Object.keys(item).some(function(key) {
if (key === '$$hashKey') { return false; }
var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
var currentVal = $scope.searchParams[searchKey].toLowerCase();
var match = item[key].toLowerCase().match(currentVal);
return currentVal.length > 1 && match;
});
};
};
Lastly, to perfectly mimic filter:searchParams, you'd just put in a check to NOT filter the items until there is user input and the input is long enough to start the partial match.
Live demo here.
$scope.searchData = function() {
var partialMatchLength = 2;
return function(item) {
var shouldFilter = Object.keys($scope.searchParams).some(function(key) {
return $scope.searchParams[key] && $scope.searchParams[key].length >= partialMatchLength;
});
if (!shouldFilter) { return true; }
return Object.keys(item).some(function(key) {
if (key === '$$hashKey') { return false; }
var searchKey = key.charAt(0).toLowerCase()+key.slice(1);
var currentVal = $scope.searchParams[searchKey].toLowerCase();
var match = item[key].toLowerCase().match(currentVal);
return currentVal.length >= partialMatchLength && match;
});
};
};
First of all you ng-repeter with 50.000 records more likely is going to kill your browser, so you should thing about pagination.
Secondly you can easy filter your data using angular filter please see that demo
http://plnkr.co/edit/R8b8G4xCMSQmX1144UJG?p=preview
<div ng-controller="ListCtrl">
<br />
First Name:
<input type="text" id="txtFirstname" ng-model="searchParams.FirstName">
<br/>Last Name:
<input type="text" id="txtLastname" ng-model="searchParams.LastName">
<br/>Email Address:
<input type="text" id="txtEmailAddress" ng-model="searchParams.EmailAddress">
<br/>Address 1:
<input type="text" id="txtAddress1" ng-model="searchParams.Address1">
<br/>Address 2:
<input type="text" id="txtAddress2" ng-model="searchParams.Address2">
<br/>
<button class="btn btn-primary" ng-click="searchData()">Search</button>
<br />
<hr />
<b>Filtered Data(s):</b>
<div ng-repeat="data in actualData | filter:searchParams ">
<span ng-bind="data.FirstName"></span>
<span ng-bind="data.LastName"></span> |
Address : {{data.Address1}}
</div>
<hr />
</div>

Display selected items in select box that is stored in database using angularjs laravel

I am trying to get a stored value from the database into a select box, but it is not displaying. The selected value shows in the console(inspect element) but it's just not displaying.
HTML
<td data-ng-class="{'has-error': employeeSchedule.employee.$invalid && employeeSchedule.employee.$dirty}">
<select class="form-control input-sm" name="employee" ng-model="schedule.employee" ng-init="schedule.employee='{{$schedules[0]->employee}}'" ng-options="employee.employeeName for employee in employeesName track by employee.usersId">
<option value="">Select Employee</option>
</select>
</td>
ANGULARJS
app.controller('UpdateWorkScheduleCtrl', [ '$scope', '$http', function ($scope, $http)
{
$http.get('/schedule/employees').success(function(employeedata) {
$scope.employeesName = employeedata;
});
}]);
CONTROLLER(LARAVEL)
public function getEmployees() {
$users = DB::select(DB::raw("SELECT `usersId`, CONCAT(`firstName`,' ',`middleName`,' ',`lastName`) AS employeeName
FROM `users`
WHERE `userStatus` != 'Administrator'
AND `userStatus` != 'Director'
AND `userStatus` != 'HR Specialist'"));
return Response::json($users);
} // end function getEmployees()
INSPECT ELEMENTS(CHROME)
It is clear from inspect elements that the data is there, but it is just not being displayed as the selected item in the select box. Can someone show me what I am doing wrong please.
Your ng-options expression does not match with what you need. You have track by employee.usersId in the syntax employee.employeeName for employee in employeesName track by employee.usersId, Which means that you would need to set ng-model to userId instead of name and also as an object not just as string, i.e your ng-model should ideally be schedule.employee = {usersId:'someid'} for default selection. Now coming to your case which pretty seems like you are trying to set ng-model as a string and you want it the name of the employee (Which probably is a poor choice since you already have an id) you should try the alternate syntax with select as label for value in array`:
ng-options="employee.employeeName as employee.employeeName for employee in employeesName "
Also remember when you use select as syntax you should remove track by, as they are not designed to work together.
Side Note:-
It is a bad idea to use ng-init for initializing ng-mode. And doc says:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.

Filtering a dropdown in Angular

I have a requirement for a select html element that can be duplicated multiple times on a page. The options for these select elements all come from a master list. All of the select elements can only show all of the items in the master list that have not been selected in any of the other select elements unless they just were duplicated.
When you select a new item from a duplicated select element, it seems to select the option after the one you selected even though the model still has the correct one set. This always seems to happen in IE11 and it happens sometimes in Chrome.
I realize this sounds convoluted, so I created a jFiddle example.
Try these steps:
Select Bender
Click the duplicate link
Select Fry (on the duplicated select)
Notice that the one that is selected is Leela but the model still has Fry (id:2) as the one selected
Can anyone tell me how I might get around this or what I might be doing wrong?
Here is the relevant Angular code:
myapp.controller('Ctrl', function ($scope) {
$scope.selectedIds = [{}];
$scope.allIds = [{ name: 'Bender', value: 1},
{name: 'Fry', value: 2},
{name: 'Leela', value: 3 }];
$scope.dupDropDown = function(currentDD) {
var newDD = angular.copy(currentDD);
$scope.selectedIds.push(newDD);
}
});
angular.module('appFilters',[]).filter('ddlFilter', function () {
return function (allIds, currentItem, selectedIds) {
//console.log(currentItem);
var listToReturn = allIds.filter(function (anIdFromMasterList) {
if (currentItem.id == anIdFromMasterList.value)
return true;
var areThereAny = selectedIds.some(function (aSelectedId) {
return aSelectedId.id == anIdFromMasterList.value;
});
return !areThereAny;
});
return listToReturn;
}
});
And here is the relevant HTML
<div ng-repeat="aSelection in selectedIds ">
Duplicate
<select ng-model="aSelection.id" ng-options="a.value as a.name for a in allIds | ddlFilter:aSelection:selectedIds">
<option value="">--Select--</option>
</select>
</div>
Hi I have just made a small change in your dupDropDown function as follows
$scope.dupDropDown = function(currentDD) {
$scope.selectedIds.push({});
}
Please check if this works for you.