I understand that 2000 options in a select box is going to bring along some performance issues, but it works fine on Chrome and Firefox and Safari.
Basically, I am calling a web service which populates a select box. This is fairly quick and performance is fine on initial load. The issue is when I change routes, and then come back to the page with the select box on it. It takes ~40 seconds to load the view on IE. Is there anyway way to improve performance?
This is how it is set up:
<select name="" id="" ng-model="model.searchParams.shipto" ng-options="ship.cd as ship.cd + (ship.cd===''?'' : ' - ') + ship.ds for ship in shiptoSelect" class="dropdownbar"></select>
This is the call that is made to retrieve the results. This is only executed once, and then the results are stored in my globalParams. So when I return to this view, this is not executed and the results are loaded from my globalParams service. That is when I run into performance issues.
$scope.getShipTo = function() {
$scope.model.searchParams.shipto = '';
$scope.model.showProgress = true;
MagicAPI.getShipToResults($scope.model.searchParams.brand, $scope.model.searchParams.soldto).then(function(response) {
if (response.status === 200) {
var resSHIPAR = eval(response.data);
var resSHIPStr = resSHIPAR;
if (resSHIPStr.length * 1 === 0) {
globalParams.getAlertList().push({
type: 'info',
msg: 'No ship-to\'s exist for this account.'
});
$scope.model.showProgress = false;
return;
} else {
var selectObj = {
cd: '',
ds: '-- select --'
};
resSHIPStr.splice(0, 0, selectObj);
globalParams.setShipToList(resSHIPStr);
$scope.shiptoSelect = resSHIPStr;
$scope.model.showProgress = false;
for (var i = 0; i < resSHIPStr.length; i++) {
if(resSHIPStr[i].cd === $scope.model.searchParams.soldto) {
$scope.isSoldToMatch = true;
return;
} else {
$scope.isSoldToMatch = false;
}
}
if ($scope.isSoldToMatch === false) {
globalParams.getAlertList().push({
type: 'info',
msg: 'No ship-to\'s exist for this account.'
});
}
}
}
}, function(response) {
$log.debug(response);
});
};
You should really read about track by and implement it
https://docs.angularjs.org/api/ng/directive/ngOptions
then your select becomes
<select name="" id=""
ng-model="model.searchParams.shipto"
ng-options="ship.cd as ship.cd + (ship.cd===''?'' : ' - ') + ship.ds for ship in shiptoSelect track by ship.id" class="dropdownbar"></select>
Related
I am very new to web development and I've been searching around for a while now and I can't seem to find a solution to this. I am using razor pages in asp.net core 2.0 and I want to fill a drop down box based on another drop down box's selection. I set up the below javascript to hit a procedure in my razor page when the value of the first drop down box changes. When I run the code though, I can't get it to work. I think it is due to my return value but I can't seem to get that to be a json value as it keeps throwing an error at me when I try to. The error is that "JSON is not valid in this context". Can anyone suggest to me how to return JSON from razor pages to a javascript call?
Any help would be appreciated!
#section Scripts {
<script type="text/javascript">
$('#Department').change(function () {
var selectedDepartment = $("#Department").val();
var cardSelect = $('#Card');
cardSelect.empty();
if (selectedDepartment != null && selectedDepartment != '') {
$.getJSON('#Url.Action("GetCardsByDivisionAndStatus")', { divisionID: selectedDepartment }, function (cards) {
if (cards != null && !jQuery.isEmptyObject(cards)) {
cardSelect.append($('<option/>', {
Card_ID: null,
Card_Number: ""
}))
$.each(cards, function (index, card) {
cardSelect.append($('<option/>', {
Card_ID: card.Card_ID,
Card_Number: card.Card_Number
}));
});
};
});
}
});
</script>
}
And here is my C# code (I tried used JsonResult but that's not working either):
// If the user selects a division then make sure to get the cards for that division only
[HttpGet]
public ActionResult GetCardsByDivisionAndStatus(string divisionID)
{
int checkinStatus;
int intdivisionID;
if (divisionID != "0" && divisionID != null)
{
// Retrieve a status of checked in so that only cards with a checked in status can
// be checked out.
checkinStatus = linqQuery.GetCardStatusByStatusDesc("Checked In", _Context);
intdivisionID = Convert.ToInt32(divisionID);
// Retrieve list of cards that have the checkin status ID
CardList = linqQuery.GetCardListByStatusIDandDeptID(checkinStatus, intdivisionID, _Context);
// Create the drop down list to be used on the screen.
carddropdown = new List<CardDropDown>();
carddropdown = loaddropdowns.ReturnDropDownList(CardList);
return new JsonResult(CardList);
}
return null;
}
EDIT----------------------------------------------------------------------
So I changed the code as below and now I'm getting a parse error "JSON.parse: unexpected character at line 1 column 1 of the JSON data" I can't figure out what is going on as I can't see what the data is coming back that it can't parse. Is my code below not converting to JSON and if not, what am I missing?
#section Scripts {
<script type="text/javascript">
$('#Department').change(function () {
var selectedDepartment = $("#Department").val();
var cardSelect = $('#Card');
cardSelect.empty();
if (selectedDepartment != null && selectedDepartment != '') {
$.getJSON('#Url.Action("/CheckOutCard?handler=CardsByDivisionAndStatus")', { divisionID: selectedDepartment }, function (cards) {
if (cards != null && !jQuery.isEmptyObject(cards)) {
cardSelect.append($('<option/>', {
Card_ID: null,
Card_Number: ""
}))
$.each(cards, function (index, card) {
cardSelect.append($('<option/>', {
Card_ID: card.Card_ID,
Card_Number: card.Card_Number
}));
});
};
});
}
});
</script>
And here is my C# code for the procedure that I updated:
// If the user selects a division then make sure to get the cards for that division only
[HttpGet]
public JsonResult OnGetCardsByDivisionAndStatus(string divisionID)
{
int checkinStatus;
int intdivisionID;
if (divisionID != "0" && divisionID != null)
{
// Retrieve a status of checked in so that only cards with a checked in status can
// be checked out.
checkinStatus = linqQuery.GetCardStatusByStatusDesc("Checked In", _Context);
intdivisionID = Convert.ToInt32(divisionID);
// Retrieve list of cards that have the checkin status ID
CardList = linqQuery.GetCardListByStatusIDandDeptID(checkinStatus, intdivisionID, _Context);
// Create the drop down list to be used on the screen.
carddropdown = new List<CardDropDown>();
carddropdown = loaddropdowns.ReturnDropDownList(CardList);
var converted = JsonConvert.SerializeObject(carddropdown);
return new JsonResult(converted);
}
return null;
}
Rename your method to OnGetCardsByDivisionAndStatus (note "OnGet" prefix) and in jquery code change the url to
$.getJSON('/{PageRoute}?handler=CardsByDivisionAndStatus'
e.g.
$.getJSON('/About?handler=CardsByDivisionAndStatus'
Notice the handler querystring parameter name will be your method name without OnGet prefix.
So I figured out what the problem was. Apparently I did not need to have the #URL.Action in my code. It was causing me to not hit my C# code which in return caused a null response back to my call. I have modified my javascript code to be as below to show what I am talking about. Thanks Mohsin for trying to help me out.
#section Scripts {
<script type="text/javascript">
$('#Department').change(function ()
{
var selectedDepartment = $("#Department").val();
var cardSelect = $('#Card');
cardSelect.empty();
if (selectedDepartment != null && selectedDepartment != '')
{
$.getJSON("/CheckOutCard?handler=CardsByDivisionAndStatus", { divisionID: selectedDepartment }, function (cards)
{
$.each(cards, function (index, card)
{
cardSelect.append($('<option/>',
{
value: card.card_ID,
text: card.card_Number
}));
});
});
}
});
</script> }
I have big component which works like x-editable plugin: when user cliks on field it becomes editable, when user clicks outside - field becomes simple text and request with new data is sent to server for validation and storing of new value.
When server returns code 200 (validation has passed) - everything is ok.
When server returns code 403 with error text inside body of response - any subsequent clicks do not trigger update event;
Here is excerpt from my vue.js component (function which is called whenever input is changed)
onInputChange() {
switch(this.inputType) {
case "select":
this.value = this.input.select2("val");
break;
case "date":
let d = this.input.datepicker("getDate");
if(d) {
this.value = moment(d).format("DD/MM/YYYY");
}
break;
case "phone":
this.value = this.input.val();
break;
case "password":
this.value = this.input.val();
break;
}
if(this.postUrl) {
let self = this;
self.errorText = "";
self.isProcessing = true;
this.$http.post(this.postUrl, {
name: this.name,
pk: this.pk,
value: this.value
}).then((response) => {
// saved
self.isProcessing = false;
if(self.isEnabled) {
switch(self.inputType) {
case "date":
self.input.datepicker("hide");
break;
}
self.isEnabled = false;
}
if(self.model && self.pk) {
window.VueBus.$emit(self.model + "_" + self.pk);
}
}, (response) => {
self.errorText = response.body;
self.isProcessing = false;
})
}
},
This is an error, which I see in console
app-vue.js:1860 POST http://localhost:8000/user/edit 403 (Forbidden)
In network tab I see that request returned correct error message: "Input too short"
For some reason this diff resolved the problem
## -5,7 +5,7 ##
'form-group': true,
'floating-label-form-group': true,
'col-lg-12': true,
- 'has-error': errorText,
+ 'has-error': errorText.length,
'floating-label-form-group-with-value': value.length > 0,
'floating-label-form-group-editing': isEnabled
}"
## -110,7 +110,7 ##
</span>
- <p class="help-block" v-if="errorText">
+ <p class="help-block" v-show="errorText.length">
{{ errorText }}
</p>
I replaced errorText with errorText.length in template. In all cases errorText is just a string (without html formatting).
I have a table with three different levels of data, when I call the child level of data using an ng-click the data is diplayed ok but when I call the grandson level the data is not displayed, the response of my WS is ok because I can see it loged in my console so I after some time I realized that I need to nest my ng-repeat's in order to display the data from the grandson level but I don get how to do it, I checked also the ng-repeat-start directive but dont know if it apply to my htlm structure, this is what I have on my view.
<table class="table table-bordered drilldown-table" id="fixTable" style="height: 505px">
<tbody ng-repeat="cat in (exportData.result.slice(0, exportData.result.length-2))" >
<tr class="parent">
<td ng-click="drillDownSubcategoriesCat(cat.merchMetrics.DEPT_NBR,cat.merchMetrics.CATG_GRP_NBR,cat.merchMetrics.DEPT_CATG_NBR)" drill-down>+</td>
<td style="text-align: left">{{cat.merchMetrics.DEPT_CATG_DESC}}</td>
<!--SALES-->
<td>{{cat.merchMetrics.SALES_AMOUNT_LW | number : 2}}</td>
<td>{{cat.merchMetrics.SALES_LW_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_L4W_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_L13W_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_L52W_CHG_LY}}%</td>
<td>{{cat.merchMetrics.SALES_LW_VS_L13W}}</td>
</tr>
<tr ng-repeat="subcat in drillDownSubcatCatList['D' + cat.merchMetrics.DEPT_NBR + 'CG' + cat.merchMetrics.CATG_GRP_NBR + 'C' + cat.merchMetrics.DEPT_CATG_NBR]" class="child" ng-if="!$last" style="background-color: #f3eee9">
<td ng-click="drillDownCategoryItemsCat(subcat.merchMetrics.DEPT_NBR, subcat.merchMetrics.CATG_GRP_NBR, subcat.merchMetrics.DEPT_CATG_NBR, subcat.merchMetrics.DEPT_SUBCATG_NBR)" drill-down>+</td>
<td style="text-align: left; padding-left: 25px">{{subcat.merchMetrics.DEPT_SUBCATG_DESC}}</td>
<!--SALES-->
<td>{{subcat.merchMetrics.SALES_AMOUNT_LW | number : 2}}</td>
<td>{{subcat.merchMetrics.SALES_LW_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_L4W_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_L13W_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_L52W_CHG_LY}}%</td>
<td>{{subcat.merchMetrics.SALES_LW_VS_L13W}}</td>
</tr>
<tr ng-repeat="items in drillDownCategoryItemCatList[nbrSubcatItem]" class="grandson" ng-if="!$last" style="background-color: #f3eee9">
<td></td>
<td style="text-align: left; padding-left: 45px">{{items.merchMetrics.DEPT_SUBCATG_DESC}}}</td>
<!--SALES-->
<td>{{items.merchMetrics.SALES_AMOUNT_LW | number : 2}}</td>
<td>{{items.merchMetrics.SALES_LW_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_L4W_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_L13W_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_L52W_CHG_LY}}%</td>
<td>{{items.merchMetrics.SALES_LW_VS_L13W}}</td>
</tr>
</tbody>
To generate the data from the child and grandson level I call to functions.
$scope.drillDownSubcatCatList = {};
$scope.subcatNbr = '';
$scope.drillDownSubcategoriesCat = function (dept,group,catg) {
$scope.nbr1 = [dept];
$scope.nbr2 = [group];
$scope.nbr3 = [catg];
$scope.nbrSubcat = 'D' + $scope.nbr1 + 'CG' + $scope.nbr2 + 'C' + $scope.nbr3;
$scope.nbrSubcat.toString();
$scope.subCategoryConst = ['Product Sales (Subcategory Rank)'];
$scope.drillDownRecords = "5";
console.log($scope.nbr1);
console.log($scope.nbr2);
console.log($scope.nbr3);
console.log("NBR: " + $scope.nbrSubcat);
if (!($scope.nbrSubcat in $scope.drillDownSubcatCatList)) {
$scope.loadViewCategories = false;
$scope.graphLoading = "loading";
searchFactory.search('merchandise',
{
timeStamp: $scope.dateTime,
timeFrameType: $scope.whenType,
custMembSelectionType: $scope.customerType,
locationSelectionType: $scope.locationType,
merchandiseSelectionType: "Category",
startYear: $scope.whenStartParentYear,
endYear: $scope.whenStartParentYear,
startUnit: $scope.whenStartValue,
endUnit: $scope.whenStartValue,
comparator: $scope.locationType.indexOf('(Comp)', $scope.locationType.length - '(Comp)'.length) !== -1,
locationSelections: $scope.locationSelected,
merchandiseSelections: [$scope.nbrSubcat],
custMembSelections: $scope.customerSelected,
metricSelections: $scope.subCategoryConst,
rankOrder: $scope.drillDownRecords
}).success(function (data) {
console.log("drillDownSubcategories OK");
$scope.loadViewCategories = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.exportDataCategoryDrillDown = data;
$scope.metricSelected = $scope.filters.baropt.displayName;
if (data.error) {
$scope.noData = "There are no results based on your selected dropdowns. Please change your selection.";
$scope.data = undefined;
$scope.hasError = true;
}
$scope.isExportDisabled = 'auto';
if (!$scope.drillDownSubcatCatList[$scope.nbrSubcat]) {
$scope.drillDownSubcatCatList[$scope.nbrSubcat] = $scope.exportDataCategoryDrillDown.result;
}
}).error(function (ret, status) {
console.log(ret, status);
if (status == 500 || status == 0) {
if (ret.error.indexOf("Filter criteria not found!") > -1 || ret.error.indexOf("Bad Selections!") > -1) {
$scope.errorMessage = "The combination of dropdowns you selected is invalid. Please select a different combination.";
} else {
$scope.errorMessage = "The database may be down. Please contact Data Cafe Development Team - Applications for help.";
}
} else if (status == 400) {
$scope.errorMessage = "There was a bad request sent to the database. Please contact Data Cafe Development Team - Applications for help.";
} else {
$scope.errorMessage = "There was an error while trying to process your request. Please contact Data Cafe Development Team - Applications for help.";
}
$scope.hasError = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.showCaptions = false;
}
);
}
if($scope.nbrSubcat in $scope.drillDownSubcatCatList) {
console.log("--------------- " + $scope.nbrSubcat);
console.log("RETURN DD SUBCATEGORY LIST: ", $scope.drillDownSubcatCatList);
}
}
And this is the second function:
$scope.drillDownCategoryItemCatList = {};
$scope.drillDownCategoryItemsCat = function (dept,group,catg,subcat) {
$scope.nbr1 = [dept];
$scope.nbr2 = [group];
$scope.nbr3 = [catg];
$scope.nbr4 = [subcat];
$scope.nbrSubcatItem = 'D' + $scope.nbr1 + 'CG' + $scope.nbr2 + 'C' + $scope.nbr3 + 'SC' + $scope.nbr4;
$scope.nbrSubcatItem.toString();
$scope.ItemsConst = ['Product Sales (Item Rank)'];
$scope.drillDownRecords = "5";
console.log($scope.nbr1);
console.log($scope.nbr2);
console.log($scope.nbr3);
console.log($scope.nbr4);
console.log("NBR: " + $scope.nbrSubcatItem);
if (!($scope.nbrSubcatItem in $scope.drillDownCategoryItemCatList)) {
$scope.loadViewCategories = false;
$scope.graphLoading = "loading";
searchFactory.search('merchandise',
{
timeStamp: $scope.dateTime,
timeFrameType: $scope.whenType,
custMembSelectionType: $scope.customerType,
locationSelectionType: $scope.locationType,
merchandiseSelectionType: "SubCategory",
startYear: $scope.whenStartParentYear,
endYear: $scope.whenStartParentYear,
startUnit: $scope.whenStartValue,
endUnit: $scope.whenStartValue,
comparator: $scope.locationType.indexOf('(Comp)', $scope.locationType.length - '(Comp)'.length) !== -1,
locationSelections: $scope.locationSelected,
merchandiseSelections: [$scope.nbrSubcatItem],
custMembSelections: $scope.customerSelected,
metricSelections: $scope.ItemsConst,
rankOrder: $scope.drillDownRecords
}).success(function (data) {
console.log("drillDownCategortyItems OK");
$scope.loadViewCategories = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.exportDataCategoryItemDrillDown = data;
$scope.metricSelected = $scope.filters.baropt.displayName;
if (data.error) {
$scope.noData = "There are no results based on your selected dropdowns. Please change your selection.";
$scope.data = undefined;
$scope.hasError = true;
}
$scope.isExportDisabled = 'auto';
if (!$scope.drillDownCategoryItemCatList[$scope.nbrSubcatItem]) {
$scope.drillDownCategoryItemCatList[$scope.nbrSubcatItem] = $scope.exportDataCategoryItemDrillDown.result;
}
}).error(function (ret, status) {
console.log(ret, status);
if (status == 500 || status == 0) {
if (ret.error.indexOf("Filter criteria not found!") > -1 || ret.error.indexOf("Bad Selections!") > -1) {
$scope.errorMessage = "The combination of dropdowns you selected is invalid. Please select a different combination.";
} else {
$scope.errorMessage = "The database may be down. Please contact Data Cafe Development Team - Applications for help.";
}
} else if (status == 400) {
$scope.errorMessage = "There was a bad request sent to the database. Please contact Data Cafe Development Team - Applications for help.";
} else {
$scope.errorMessage = "There was an error while trying to process your request. Please contact Data Cafe Development Team - Applications for help.";
}
$scope.hasError = true;
$scope.graphLoading = "white";
$scope.canvasContent = true;
$scope.showCaptions = false;
}
);
}
if($scope.nbrSubcatItem in $scope.drillDownCategoryItemCatList) {
console.log("LIST FROM CATEGORY TO ITEM LEVEL: ", $scope.drillDownCategoryItemCatList);
}
}
As I mentioned before, the parent and the child level are displayed ok, so any idea on how can I nest the ng-repeat's in order to allow my grandson level to be displayed?
There is something strange here that you require a single table in the UI, but the underlying model is of a triply nested object. ng-repeat is not meant to be nested at sibling DOM levels.
The way I would recommend implementing this is to use an angular filter that will wrap all of your data into a single array that you can call ng-repeat on.
Your controller has wayyyyy too much logic in it. And I think this is contributing to the difficulties. In general, the controller should be in charge of displaying data that is being provided by angular services. The angular services should provide the data in a way that is easy for the controllers to consume.
If you find yourself creating nested if statements, xhr requests, and error handling inside of the controller, then you are doing something wrong. All of this should be refactored to several services (each service should have a SINGLE responsibility). Then you should have one of the services provide data to the controller that is easy for it to consume.
This is a bit of a vague answer, and not really a simple one. I think that the problems you are having come from not fully understanding how Angular implements the MVC pattern.
I'm using code I found online to convert a standard option set field to a checkbox in MS CRM 2015 online. It keeps giving me the above error.
Here is the code:
function MultiPickList3(param1, param2, param3,param4,param5)
{
try
{
var fn = arguments.callee.toString().match(/function\s+([^\s\(]+)/);
if (param1==null || param2==null)
{
alert("Error: Parameter missing. \n Format: <optionset fieldname> , <option value text field> , [<option header>], [<select color>] , [<deselect color>] , \n ["+"Function="+fn[1]+"]" );
return true;
}
var tparamtype=Xrm.Page.data.entity.attributes.get(param1).getAttributeType();
if (tparamtype!="optionset")
{ alert (param1+"(first parameter) should be of type optionset \n"+"[function="+fn[1]+"]");
return true;
}
var tparamtype=Xrm.Page.data.entity.attributes.get(param2).getAttributeType();
if (tparamtype!="memo")
{ alert (param2+"(second parameter) should be of type memo (text with mutiline) \n[function="+fn[1]+"]");
return true;
}
var plOptions=param1;
var plText=param2;
var plMenuItem="View Selected List";
var SelectedList_orig = crmForm.all[plText];
var FullList=crmForm.all[plOptions];
var SelCtr=-1;
var new_selColor="orange";
var new_deSelColor="white";
if (param4!=null)
new_selColor=param4;
if (param5!=null)
new_deSelColor=param5;
var SelectedList =SelectedList_orig.value.split("\r\n");
crmForm.all[plText].style.display="none";
if(FullList!=null && SelectedList!=null)
{
initColor();
if (param3!=null && param3!="")
{
plMenuItem=param3;
}
else
{
plMenuItem=FullList.options[0].text;
changeColor("grey",0);
}
for (var ctr=0; ctr<SelectedList.length;ctr++)
{
selCtr=SelectedIndex(SelectedList[ctr]);
if (selCtr >-1)
{
changeColor(new_selColor,selCtr);
}
}
}
function SelectedIndex(selectedText)
{
var FullListText;
for (var ctr1=0; ctr1<FullList.options.length;ctr1++)
{
FullListText=FullList.options[ctr1].text;
if ( FullListText==selectedText)
{
return ctr1;
}
}
return -2;
}
crmForm.all[plOptions].attachEvent('onchange', OnChangePL);
function OnChangePL()
{
var SelCtr=-1;
var sel=crmForm.all[plOptions].SelectedText;
if (sel==plMenuItem)
return;
SelCtr=SelectedIndex(sel);
var SelColor="grey";
SelColor=crmForm.all[plOptions][SelCtr].style.backgroundColor;
if (SelColor==new_selColor)
{
changeColor(new_deSelColor,SelCtr);
saveChanges(sel,selCtr,"del");
}
else
{
changeColor(new_selColor, SelCtr);
saveChanges(sel,selCtr,"add");
}
}
function saveChanges(p_selText,p_SelCtr,p_mode)
{
switch(p_mode)
{
case "add":
SelectedList.push(p_selText);
break;
case "del":
for (var ctr2=0;ctr2<SelectedList.length;ctr2++)
{
if (SelectedList[ctr2]==p_selText)
{
SelectedList.splice(ctr2,1);
break;
}
}
break;
}
Xrm.Page.getAttribute(plText).setValue(SelectedList.join("\r\n"));
}
function initColor()
{
for (var ctr3=0; ctr3<FullList.options.length;ctr3++)
{ changeColor(new_deSelColor, ctr3); }
}
function changeColor(newColor, newCtr)
{
crmForm.all[plOptions][newCtr].style.backgroundColor=newColor;
}
}
catch (e)
{ alert (e.description);}
}
param2 takes the field "new_textholder" which is a multiline text field. It's defined on the form and I have checked to make sure I am writing it correctly.
What could be the problem?
Thank you!!
This error is likely coming from the crmForm.all[plText] line. I'm guessing your org is recent enough that support for the old 4.0 api is no longer present, which would mean that the all object is no longer available, which would give you that error (plText is set to the value of param2). You might be able to modify this code to work on your 2015 form, but I don't have a 2015 org available to me at the moment so I can't say for sure.
I am using https://github.com/localytics/angular-chosen to allow for select tags with search capability for many options.
The problem I'm having is with preselecting an option on an already saved vendor object. When creating a new one there is now issue, but if we're viewing an existing vendor, I want to show the vendor's name in the select box, rather than the placeholder.
<select chosen
ng-model="myVendor"
ng-options="vendor['public-id'] as vendor.name for vendor in vendors"
data-placeholder="Nah">
</select>
And in my controller, I'm setting the model by hand $scope.myVendor = "Some value"
The problem is that I'm populating the options with an object, instead of a key/value. I found an example of it working with a key/value, but haven't had success adapting this to objects as options.
I've even tried setting myVendor to the matching object that I want selected, with no luck.
Plunker of issue
I updated the plunker and change my previous changes on the plugin. this was not the issue. I don't understand how it was giving me errors there.
The solution is to track with an object and two functions the id and the name:
// Controller
$scope.vendors = [
{
"public-id": "1234",
"name": "stugg"
},
{
"public-id": "4321",
"name": "pugg"
}
];
$scope.myVendor = {name: "pugg", id:""};
$scope.updateMyVendorName = function () {
var found = false,
i = 0;
while (!found && i < $scope.vendors.length) {
found = $scope.vendors[i]['public-id'] === $scope.myVendor.id;
if (found) {
$scope.myVendor.name = $scope.vendors[i].name;
}
i++;
}
}
findVendorByName();
function findVendorByName () {
var found = false,
i = 0;
while (!found && i < $scope.vendors.length) {
found = $scope.vendors[i]['name'] === $scope.myVendor.name;
if (found) {
$scope.myVendor.id = $scope.vendors[i]['public-id'];
}
i++;
}
}
// template
<select chosen class="form-control span6" ng-options="vendor['public-id'] as vendor.name for vendor in vendors" ng-model="myVendor.id" ng-change="updateMyVendorName()">
{{myVendor.name}}