Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I've been working a project that allows a user to manage Option Types and Options. Basically user can add a new Option Type, let's say they name it Color and then they add the options - Black, Red, Purple, etc. When the collection first loads up the existing records, an empty option should be added at the end

When a user starts typing in the text field, I want to add a new empty option , thereby always giving the user a new field to work with.

I have this almost working, but can't figure how to properly add new empty option to a new Option Type or to existing option types. The push method keeps crashing Plunkr. Any input is appreciated, short sample review of the 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

share|improve this question
    
so whats your issue? – user3727843 Jul 2 '15 at 17:58
    
Issue is that I am unable to figure out how to add a new option to each option type when user types into the field. Then another issue occurs with the indexes when a user adds a new Option Type. – Mike Anderson Jul 2 '15 at 18:03
    
Still unclear but I think you want to use an ng-repeat bound to a list of options and another for each option's list of optionTypes – user3727843 Jul 2 '15 at 18:34
    
I updated the Plunkr, everythign is working but the add empty option. can't figure it out, sorry for the lack of clarity, its rough trying to write code and babysit two kids lol – Mike Anderson Jul 2 '15 at 21:35
up vote 0 down vote accepted

The error you get that $ is not defined is because you haven't included jQuery. You don't need jQuery for this though, array.map should be able to perform the same functionality.

$scope.emptyElements = $scope.productEditorModel.ProductOptions.map(function (k) { 
   return k.OptionValue === "" || angular.isUndefined(k.OptionValue) && k.OptionTypeId == optionTypeId 
});

And it crashes because inside $scope.loadData you have

angular.forEach($scope.productEditorModel.ProductOptions, function (item) {
    $scope.addEmptyOption(item.OptionTypeId);
});

and then inside $scope.addEmptyOption you try to

$scope.productEditorModel.ProductOptions.push(emptyOption);

So the foreach will loop for each item in $scope.productEditorModel.ProductOptions, which you keep adding options to so....? Infinite loop.

Non-crashing version: http://plnkr.co/edit/5Sc2sWfhKBs9kLCk83f1?p=preview

What you really should do though is look over your data structure. Make the ProductOptions a sub-object of OptionTypes and just rename it Options. Remove ALL code about creating id's here in your GUI, that should be handled by the backend. Instead in the GUI there should be a Sortorder property on the Options (which also of course gets stored by the backend). Then when you store, the ones without an id get inserted, the ones with an id get updated. Much easier to handle everything that way.

I'd also break out optionTypes and options to their own services/providers. Much easier to keep track of what needs to be done. And each just basically contains add, remove and maybe a find/getJSON or something.

Here's a restructured version. Much easier to keep track of what belongs where. And it has more features than the original with less code. http://plnkr.co/edit/BHcu6vAfcpEYQpZKHc5G?p=preview

share|improve this answer
    
Thanks for that, I'm kinda new to angular so I totally forgot that the loop would be infinite. What do you think about using ng-init to call loadData, I believe ng-init is only executed once. – Mike Anderson Jul 3 '15 at 16:05
    
The problem isn't with executing once, the problem is that you're adding items to the array you're iterating over for each iteration over the array. Kinda like if you were doing this. while (i < j) { i++; j++; }. if i is smaller than j to begin with, i will always be smaller than j since you're increasing both so you will never exit the loop. But why do you need to add items to ProductOptions if the items are there to begin with? You probably want to load them from a setting file/json/sql call, and then you could just bind the loaded array to ProductOptions, no need to iterate. – Jan Jul 3 '15 at 16:21
    
Here's a mock of what you'd actually want to be doing. Suggestions for fixing a few other bugs too. plnkr.co/edit/t0hUTt6u1UcTxYyKRGEd?p=preview – Jan Jul 3 '15 at 16:55
    
Thanks for the knowledge...the reason why I want to add items to existing ProductOptions is because I always want a new empty option there for the user to work with. – Mike Anderson Jul 3 '15 at 17:26
1  
Lol, after my 2nd cup of coffee I realized I should set it local to the object, not to the global scope like you mentioned :) I need to treat angular just like regular OOP code, b/c it's pretty much the same in regards to objects, scope and other factors. – Mike Anderson Jul 4 '15 at 13:33

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.