Angular JS Empty Object Path to Array
I am working on a project that allows the user to control options and options. Basically the user can add a new type of parameter, let him name it “Color” and then add options “Black”, “Red”, “Purple”, etc. When the collection first loads existing entries, add an empty option at the end
When the user starts typing a text box, I want to add a new blank option, thus always presenting the user with a new field to work with.
It almost works for me, but I can't figure out how to properly add a new empty option to a new Option type or existing option types. The push method keeps crashing Plunkr. Any input is appreciated, an overview of the sample plunkr is below
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.optionTypeId = 0;
$scope.productOptionId = 0;
$scope.productEditorModel = {
"ProductOptions": [0],
"OptionTypes": [0]
};
$scope.productEditorModel.optionTypeName = '';
$scope.addEmptyOption = function (optionTypeId) {
var emptyOption = { ProductOptionId: 3, ProductId: '1066', OptionTypeId: 1, OptionValue: '', Price: '', IsStocked: true };
console.log(emptyOption);
//$scope.productEditorModel.ProductOptions.push(emptyOption);
};
$scope.loadData = function () {
$scope.productEditorModel.OptionTypes = [{ OptionTypeId: 1, OptionName: 'Color' },{ OptionTypeId: 2, OptionName: 'Size' },];
$scope.productEditorModel.ProductOptions = [{ ProductOptionId: 1, ProductId: '1066', OptionTypeId: 2, OptionValue: 'Medium', Price: '', IsStocked: true, },{ ProductOptionId: 2, ProductId: '1066', OptionTypeId: 1, OptionValue: 'Black', Price: '', IsStocked: true }];
angular.forEach($scope.productEditorModel.ProductOptions, function (item) {
//console.log(item.OptionTypeId);
$scope.addEmptyOption(item.OptionTypeId);
});
};
$scope.loadData();
$scope.removeOption = function (option) {
var index = $scope.productEditorModel.ProductOptions.indexOf(option);
$scope.productEditorModel.ProductOptions.splice(index, 1);
};
$scope.filterEmptyElements = function (optionTypeId) {
$scope.emptyElements = $.grep($scope.productEditorModel.ProductOptions, function (k) { return k.OptionValue === "" || angular.isUndefined(k.OptionValue) && k.OptionTypeId == optionTypeId });
};
$scope.update = function (option, index) {
var optionTypeId = option.OptionTypeId;
$scope.filterEmptyElements(optionTypeId);
if (!angular.isUndefined(option.OptionValue) && $scope.emptyElements.length == 1 && option.OptionValue.length > 0) {
$scope.addOption(optionTypeId);
} else if (angular.isUndefined(option.OptionValue)) {
$scope.removeOption(option);
}
};
$scope.addOptionType = function () {
var optionTypeId = --$scope.optionTypeId;
var optionName = $scope.productEditorModel.optionTypeName;
var newOptionType = { OptionTypeId: optionTypeId, OptionName: optionName };
$scope.productEditorModel.OptionTypes.push(newOptionType);
$scope.addEmptyOption(optionTypeId);
};
$scope.editOptionType = function (optionType) {
$scope.editing = true;
};
$scope.saveOptionType = function (optionType) {
$scope.editing = false;
};
$scope.trackOptionTypesCount = function () {
if ($scope.productEditorModel.OptionTypes.length == 3) {
$scope.isMaxOptionTypes = true;
} else {
$scope.isMaxOptionTypes = false;
}
};
$scope.removeOptionType = function (optionType) {
var index = $scope.productEditorModel.OptionTypes.indexOf(optionType);
$scope.productEditorModel.OptionTypes.splice(index, 1);
$scope.trackOptionTypesCount();
};
});
See the plunker below: http://plnkr.co/edit/YHLtSwQWVb2swhNVTQzU?p=info
source to share
The error you are getting $ is not defined
is that you have not included jQuery. You don't need jQuery to do this, but array.map
should be able to do the same functionality.
$scope.emptyElements = $scope.productEditorModel.ProductOptions.map(function (k) {
return k.OptionValue === "" || angular.isUndefined(k.OptionValue) && k.OptionTypeId == optionTypeId
});
And it will work because inside $scope.loadData
you have
angular.forEach($scope.productEditorModel.ProductOptions, function (item) {
$scope.addEmptyOption(item.OptionTypeId);
});
and then inside $scope.addEmptyOption
you try
$scope.productEditorModel.ProductOptions.push(emptyOption);
So, foreach
will loop over each item in $scope.productEditorModel.ProductOptions
which you keep adding parameters like this ....? Infinite loop.
No crashing version: http://plnkr.co/edit/5Sc2sWfhKBs9kLCk83f1?p=preview
What you really should be doing is looking at the data structure. Make ProductOptions a sub-object of OptionTypes and simply rename it Options. Remove ALL the code about creating an id here in your GUI that the backend should handle. Instead, the GUI should have a Sortorder property in the settings (which is of course also stored in the backend). Then, when you store, the ones that don't have an ID get up, the ones that have an ID are updated. It's much easier to deal with this.
I would also rip out optionsTypes and options for my own services / providers. It's much easier to keep track of what needs to be done. And each just basically contains add, remove and maybe find / getJSON or something.
Here's a restructured version. It's much easier to keep track of what belongs. And it has more features than the original with less code. http://plnkr.co/edit/BHcu6vAfcpEYQpZKHc5G?p=preview
source to share