Odd duplication in Angular repeater - angularjs

I am getting some odd behavior when I update the array that a repeater is using from a $watch
This is the HTML
<section data-ng-controller="JobsController">
<div class="page-header">
<h1>New Job</h1>
</div>
<div class="col-md-12">
<form class="form-horizontal" data-ng-submit="create()" novalidate>
<fieldset>
<div class="form-group" data-ng-controller="DisciplinesController" data-ng-init="find()">
<h3>Discipline</h3>
<div>
<!--clicking these will filter -->
<label class="form-control" data-ng-repeat="discipline in disciplines">
<input type="checkbox" checklist-model="$parent.dl" checklist-value="discipline"> {{discipline.name}}
</label>
</div>
</div>
<!--this is the updated list -->
<div class="form-group">
<h3>Roles</h3>
<div>
<label class="form-control" data-ng-repeat="role in selectedDisciplineRoles">
<input type="checkbox" checklist-model="roleList" checklist-value="role"> {{role.name}}
</label>
</div>
</div>
<div class="form-group">
<h3>What "Job" are they trying to do?</h3>
<label class="control-label" for="name">Name</label>
<div class="controls">
<input type="text" data-ng-model="name" id="name" class="form-control" placeholder="Name" required>
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-default">
</div>
<div data-ng-show="error" class="text-danger">
<strong data-ng-bind="error"></strong>
</div>
</fieldset>
</form>
</div>
</section>
What I am trying to do is have this model filter on the server and have the client update with the appropriate values
'use strict';
// Jobs controller
angular.module('jobs').controller('JobsController', ['$scope', '$stateParams', '$location', 'Authentication', 'Jobs', 'RolesAPI',
function($scope, $stateParams, $location, Authentication, Jobs, RolesAPI) {
$scope.authentication = Authentication;
$scope.$watchCollection("dl", function(){
var activeDisciplineIds = _.pluck($scope.dl, "_id");
$scope.selectedDisciplineRoles = [];
RolesAPI.getByDisciplineIds(activeDisciplineIds)
.success(function(data){
$scope.selectedDisciplineRoles = data;
console.log($scope.selectedDisciplineRoles)
}
);
});
}
]);
I don't see any duplicates on the return, however when i click on the checkbox there is a quick duplication of the all the active results, and then the duplicates disappear.
I am open to creating an angualar filter but wasn't able to get it working. Here is the data that I am dealing with.
[
{
_id: "547d2ad8b62d3f8bfaf139f8",
user: {
_id: "547648f95413b30000a03e21"
},
base: "547956b0824679a54c9142d2",
__v: 0,
created: "2014-12-02T02:58:32.422Z",
disciplines: [
"5476625147bd3200004bae00"
],
name: "item 1"
},
{
_id: "547d0012b62d3f8bfaf139f7",
user: {
_id: "547648f95413b30000a03e21"
},
base: "547956a6824679a54c9142d1",
__v: 0,
created: "2014-12-01T23:56:02.427Z",
disciplines: [
"5476616347bd3200004badfb",
"547661cb47bd3200004badfd"
],
name: "item 2"
},
{
_id: "547cfea6b62d3f8bfaf139f6",
user: {
_id: "547648f95413b30000a03e21"
},
base: "547956a6824679a54c9142d1",
__v: 0,
created: "2014-12-01T23:49:58.885Z",
disciplines: [
"547661cb47bd3200004badfd",
"5476616347bd3200004badfb"
],
name: "item 3"
}
]
The filtering needs to happen based on a match of an array of ids, and those in the disciplines array of the object.
so something like
["5476616347bd3200004badfb", "547661cb47bd3200004badfd"]
would return item 1 and item 3, not item 2

I ended up getting the filter working like this.
'use strict';
angular.module('roles').filter('rolesByDiscipline', [
function() {
return function(roles, disciplineIds) {
return roles.filter(function(role) {
for (var i in role.disciplines) {
if (_.pluck(disciplineIds, "_id").indexOf(role.disciplines[i]) != -1) {
return true;
}
}return false;
});
};
}
]);
HTML
<div class="form-group" data-ng-controller="RolesController" data-ng-init="find()">
<h3>Roles</h3>
<div>
<label class="form-control" data-ng-repeat="role in roles | rolesByDiscipline:$parent.dl">
<input type="checkbox" checklist-model="roleList" checklist-value="role"> {{role.name}}
</label>
</div>
</div>

Related

AngularJs hide all alerts: Uncaught SyntaxError

I have an angularJS component that displays alerts when something goes wrong while submitting, these alerts are not auto dismissed by design.
But, when the user fix all errors (there can be many alerts displayed on the screen) and submit I want to dismiss these alerts.
Based on this example https://jsfiddle.net/uberspeck/j46Yh/
I did something like this:
(function(){
var mainApp = angular.module("myApp");
function AlertsCtrl($scope, alertsManager) {
$scope.alerts = alertsManager.alerts;
}
mainApp.factory('alertsManager', function() {
return {
alerts: {},
addAlert: function(message, type) {
this.alerts[type] = this.alerts[type] || [];
this.alerts[type].push(message);
},
clearAlerts: function() {
for(var x in this.alerts) {
delete this.alerts[x];
}
}
};
mainApp.controller("addUserCtrl", ['Restangular', 'alertsManager', '$alert', 'roles', '$window' , function(Restangular, alertsManager, $alert, roles, $window) {
var that = this;
init();
that.submit = function() {
var data = {
user : that.name,
role : that.role.serverName,
credentials : that.password1
}
Restangular.all("admin").all("user").all("add").post(data).then(function() {
//$alert({title: 'Add User:', content: 'Completed succefully', type: 'success', container: '#alert', duration: 5, show: true});
alertsManager.addAlert('Completed succefully', 'alert-success');
init();
alertsManager.clearAlerts();
}, function(reason) {
//$alerts{title: 'Add User:', content: reason.data.error, type: 'danger', container: '#alert', show: true});
alertsManager.addAlert(reason.data.error, 'alert-error');
});
}
function init() {
that.name = "";
that.roles = roles;
that.role = that.roles[0];
that.password1 = "";
that.password2 = "";
}
}]);
})();
HTML:
<div ng-controller="addUserCtrl as ctrl">
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<form class="form-horizontal" ng-submit="ctrl.submit()">
<div class="panel-heading">Add User</div>
<div class="panel-body">
<div class="form-group">
<label for="name" class="col-sm-3 control-label">User Name: <span class="required">*</span></label>
<div class="col-sm-8">
<input type="text" class="form-control" id="name" ng-model="ctrl.name"></input>
</div>
</div>
<div class="form-group">
<label for="role" class="col-sm-3 control-label">Role: <span class="required">*</span></label>
<div class="col-sm-8">
<select class="form-control" id="role" ng-model="ctrl.role" ng-options="opt.displayName for opt in ctrl.roles"></select>
</div>
</div>
<div class="form-group">
<label for="password1" class="col-sm-3 control-label">Password: <span class="required">*</span></label>
<div class="col-sm-8">
<input type="password" class="form-control" id="password1" ng-model="ctrl.password1"></input>
</div>
</div>
<div class="form-group">
<label for="password2" class="col-sm-3 control-label">Re-enter Password: <span class="required">*</span></label>
<div class="col-sm-8" ng-class="{'has-error' : ctrl.password1 != ctrl.password2}">
<input type="password" class="form-control" id="password2" ng-model="ctrl.password2"></input>
<p class="help-block" ng-if="ctrl.password1 != ctrl.password2">Passwords don't match</p>
</div>
</div>
</div>
<div class="panel-footer">
<button type="submit" class="btn btn-default" ng-disabled="!ctrl.name || !ctrl.password1 || !ctrl.password2 || ctrl.password1 != ctrl.password2">OK</button>
</div>
<div ng-controller="AlertsCtrl">
<div ng-repeat="(key,val) in alerts" class="alert {{key}}">
<div ng-repeat="msg in val">{{msg}}</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
But I'm getting:
Uncaught SyntaxError: Unexpected end of input
angular.js:14747 Error: [ng:areq] http://errors.angularjs.org/1.4.3/ng/areq?p0=addUserCtrl&p1=not%20aNaNunction%2C%20got%20undefined
You did not complete all brackets correctly.
Below should be like this:
mainApp.factory('alertsManager', function() {
return {
alerts: {},
addAlert: function(message, type) {
this.alerts[type] = this.alerts[type] || [];
this.alerts[type].push(message);
},
clearAlerts: function() {
for(var x in this.alerts) {
delete this.alerts[x];
}
}
}
});
You forgot to complete the factory by });.
And that is why indentation is so important.
Hope this may help you.

angular form ng-repeat deleting single form

i am working with dynamic forms with ng-repeat .i am getting dynamic forms according to my userid. each form has delete button. my requirement is once i am clicking delete button i need to delete that particular form and those values from my user obj and remaining values i need to send to server. in this example i want to delete id 2 (2nd form), and 1st and 2nd form data i need to store one variable.
please send some fiddle for this .
my html code
<div ng-app="myApp">
<div ng-controller="myCtrl">
<form role="form" name='userForm' novalidate>
<div class="container">
<div class="row" ng-repeat="user in users">
<div class="form-group">
<div class="col-md-3">
<label>ID</label>
<input ng-model="user.id" id="user.id" name="user.id" placeholder="Enter bugid" type="text" required readonly disabled>
</div>
<div class="col-md-3">
<label>Comments</label>
<textarea ng-model="user.comment" id="textarea1" rows="1" required></textarea>
</div>
<div class="col-md-3 ">
<label>Location</label>
<select ng-model="user.location" ng-options="v for v in locations" ng-init='initLocation(user)' name="select2" required>
</select>
</div>
<div>
<button>delete</button>
</div>
</div>
</div>
</div>
<div class="buttonContainer text-center btn-container">
<br>
<button ng-disabled="userForm.$invalid" type="button" id="adduser" ng-click="adduser()">Add user</button>
<button type="button" class="btn button--default btn--small pull-center">Close</button>
</div>
</form>
</div>
js file
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function($scope, $timeout) {
$scope.ids = [1, 2, 3];
$scope.users = $scope.ids.map(function(id) {
return {
id: id,
comment: "",
location: ""
};
});
$scope.locations = ['india', 'usa', 'jermany', 'china', 'Dubai'];
$scope.initLocation = (user) => {
$timeout(() => {
user.location = $scope.locations[0];
});
}
$scope.adduser = function() {
var data = $scope.users.map(function(user) {
return {
"userid": user.id,
"manualcomment": user.comment,
"location": user.location
}
});
console.log("data", data)
}
});
As per your requirement i am adding ng-click to delete button and adding removeSelForm method and pass your user object into that function parameter. in controller i am removing that particular form values from users object.
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function($scope, $timeout) {
$scope.ids = [1, 2, 3];
$scope.users = $scope.ids.map(function(id) {
return {
id: id,
comment: "",
location: ""
};
});
$scope.locations = ['india', 'usa', 'jermany', 'china', 'Dubai'];
$scope.initLocation = (user) => {
$timeout(() => {
user.location = $scope.locations[0];
});
}
$scope.removeSelForm = function(item) {
var index = $scope.users.indexOf(item)
$scope.users.splice(index, 1);
}
$scope.adduser = function() {
var data = $scope.users.map(function(user) {
return {
"userid": user.id,
"manualcomment": user.comment,
"location": user.location
}
});
console.log("data", data)
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<form role="form" name='userForm' novalidate>
<div class="container">
<div class="row" ng-repeat="user in users">
<div class="form-group">
<div class="col-md-3">
<label>ID</label>
<input ng-model="user.id" id="user.id" name="user.id" placeholder="Enter bugid" type="text" required readonly disabled>
</div>
<div class="col-md-3">
<label>Comments</label>
<textarea ng-model="user.comment" id="textarea1" rows="1" required></textarea>
</div>
<div class="col-md-3 ">
<label>Location</label>
<select ng-model="user.location" ng-options="v for v in locations" ng-init='initLocation(user)' name="select2" required>
</select>
</div>
<div>
<button ng-click="removeSelForm(user)">delete</button>
</div>
</div>
</div>
</div>
<div class="buttonContainer text-center btn-container">
<br>
<button ng-disabled="userForm.$invalid" type="button" id="adduser" ng-click="adduser()">Add user</button>
<button type="button" class="btn button--default btn--small pull-center">Close</button>
</div>
</form>
</div>

Why is my $scope not working?

I'm newbie in angularJS. I have finished phone-cat tutorial on the official angular document. I am trying to create some new feature for it such as ( create a new item , edit ... ) Assume that I created api for this.
app/phone-create/phone-create.module.js
angular.module('phoneCreate', ['core.phone'])
app/phone-create/phone-create.component.js
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
var data = {
name: $scope.name,
description: $scope.description,
kind: $scope.kind
}
self.create = function () {
console.log(data); // {name : underfined , desciprion : underfined , kind : underfined}
}
}
]
});
app/phone-create/phone-create.template.html
<div class="row">
<div class="form-horizontal col-md-8">
<div class="form-group">
<label class="control-label col-sm-4" for="name">Name</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.name" class="form-control" id="name" placeholder="Name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="description">Description</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.description" class="form-control" id="description" placeholder="description">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="kind">Kind</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.kind" class="form-control" id="kind" placeholder="Kind">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<button type="submit" ng-click="$ctrl.create()" class="btn btn-default">Create</button>
</div>
</div>
</div>
</div>
When I click Create , I want to fields in input will be accessed by scope in controller but it is underfined. I don't know why and how to fix. Please help me!.
Let's take a look at these three lines:
<input type="text" ng-model="$ctrl.name" class="form-control" id="name" placeholder="Name">
<input type="text" ng-model="$ctrl.description" class="form-control" id="description" placeholder="description">
<input type="text" ng-model="$ctrl.kind" class="form-control" id="kind" placeholder="Kind">
They have ng-models: $ctrl.name, $ctrl.description, $ctrl.kind. Your component doesn't declare those variables.
Change them to $ctrl.data.name, $ctrl.data.description, $ctrl.data.kind and modify your component:
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
self.data = {
name: "",
description: "",
kind: ""
};
self.create = function () {
console.log(self.data);
};
}
]
});
OPTION 1 :
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
self.create = function () {
console.log(self.name); // {name : underfined , desciprion : underfined , kind : underfined}
}
}
]
});
OPTION 2 :
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
// No need to initialise self.data
self.data = {
name: '',
description: '',
kind: ''
}
self.create = function () {
console.log(self.data);
console.log(self.data.name);
}
}
]
});
HTML :
<div class="row">
<div class="form-horizontal col-md-8">
<div class="form-group">
<label class="control-label col-sm-4" for="name">Name</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.name" class="form-control" id="name" placeholder="Name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="description">Description</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.description" class="form-control" id="description" placeholder="description">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="kind">Kind</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.kind" class="form-control" id="kind" placeholder="Kind">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<button type="submit" ng-click="$ctrl.create()" class="btn btn-default">Create</button>
</div>
</div>
</div>
</div>

Binding ng-repeat and ng-model from controller

I'm new to AngularJS. I'm trying to build a form with ng-repeat and having trouble wrapping my head around the angular stuff.
This is my angular controller:
// Create the 'products' controller
angular.module('products').controller('ProductsController', ['$scope', '$routeParams', '$location', 'Authentication', 'Products',
function($scope, $routeParams, $location, Authentication, Products) {
// Expose the Authentication service
$scope.authentication = Authentication;
$scope.productProperty = {
productTitle: {slug: 'productTitle', label: 'Product Title', value: '', placeholder: 'Product Title'},
productCode: {slug: 'productCode', label: 'Product Code', value: '', placeholder: 'Product Code'},
productModel: {slug: 'productModel', label: 'Product Model', value: '', placeholder: 'Product Model'},
productColor: {slug: 'productColor', label: 'Product Color', value: '', placeholder: 'Product Color'}
};
// Create a new controller method for creating new products
$scope.create = function() {
// Use the form fields to create a new product $resource object
var product = new Products({
productTitle: this.productTitle,
productCode: this.productCode,
productModel: this.productModel,
productColor: this.productColor
});
// Use the product '$save' method to send an appropriate POST request
product.$save(function(response) {
// If an product was created successfully, redirect the user to the product's page
$location.path('products/' + response._id);
}, function(errorResponse) {
// Otherwise, present the user with the error message
$scope.error = errorResponse.data.message;
});
};
}
]);
HTML:
<!-- The create product view -->
<section data-ng-controller="ProductsController">
<h1>New Product</h1>
<!-- The new product form -->
<form data-ng-submit="create()" novalidate>
<div class="row" data-ng-repeat="(keyAssets, valueAssets) in productProperty">
<div>
<label for="{{productProperty[keyAssets]['slug']}}">{{productProperty[keyAssets]['label']}}</label>
<div>
<input type="text" data-ng-model="productProperty[keyAssets]['slug']" id="{{productProperty[keyAssets]['slug']}}" placeholder="{{productProperty[keyAssets]['placeholder']}}" required>
</div>
</div>
</div>
<div>
<input type="submit">
</div>
<!-- The error message element -->
<div data-ng-show="error">
<strong data-ng-bind="error"></strong>
</div>
</form>
</section>
I'm trying to get the 'data-ng-model' set to something unique in each instance of the data-ng-repeat. But I'm not getting the desired output.
I want something like the following output:
<!-- The create product view -->
<section data-ng-controller="ProductsController">
<h1>New Product</h1>
<!-- The new product form -->
<form data-ng-submit="create()" novalidate>
<div>
<label for="productTitle">Product Title</label>
<div>
<input type="text" data-ng-model="productTitle" id="productTitle" placeholder="Product Name" required>
</div>
</div>
<div>
<label for="productCode">Product Code</label>
<div>
<input type="text" data-ng-model="productCode" id="productCode" placeholder="Product Code" required>
</div>
</div>
<div>
<label for="productModel">Product Model</label>
<div>
<input type="text" data-ng-model="productModel" id="productModel" placeholder="Product Model" required>
</div>
</div>
<div>
<label for="productColor">Product Color</label>
<div>
<input type="text" data-ng-model="productColor" id="productColor" placeholder="Product Color" required>
</div>
</div>
<div>
<input type="submit">
</div>
<!-- The error message element -->
<div data-ng-show="error">
<strong data-ng-bind="error"></strong>
</div>
</form>
How can I get the 'data-ng-model' set to something unique in each instance of the ng-repeat?

Fields values generated using ng-repeat is not getting while submit

Template for form submission. This page will display the form template. Initially it shows the TItle,Full Name. On clicking the 'Add Tags' link new input fields is been generated for entering tags.
On submit, the field input(story.tag) is not been included on RequestPayload
<form novalidate ng-submit="save()">
<div>
<label for="title">Title</label>
<input type="text" ng-model="story.title" id="title" required/>
</div>
<div>
<label for="firstName">Full Name</label>
<input type="text" ng-model="story.fullname" id="fullname" required/>
</div>
<div ng-controller="Note" >
<div ng-repeat="story in items ">
<label>Tag {{$index+1}}:</label>
<input type="text" ng-model="story.tag" id="tag" required/>
</div>
<a ng-click="add()">Add Tags</a>
</div>
<button id="save" class="btn btn-primary">Submit Story</button>
</form>
script :- app.js
angular.module("getbookmarks", ["ngResource"])
.factory('Story', function ($resource) {
var Story = $resource('/api/v1/stories/:storyId', {storyId: '#id'});
Story.prototype.isNew = function(){
return (typeof(this.id) === 'undefined');
}
return Story;
})
.controller("StoryCreateController", StoryCreateController);
function StoryCreateController($scope, Story) {
$scope.story = new Story();
$scope.save = function () {
$scope.story.$save(function (story, headers) {
toastr.success("Submitted New Story");
});
};
}
//add dynamic forms
var Note = function($scope){
$scope.items = [];
$scope.add = function () {
$scope.items.push({
inlineChecked: false,
tag: "",
questionPlaceholder: "foo",
text: ""
});
};
}
The story object inside ng-repeat is in another scope. This JSFiddle should do what you are looking for.
<div ng-app>
<div ng-controller="NoteCtrl">
<form novalidate ng-submit="save()">
<div>
<label for="title">Title</label>
<input type="text" ng-model="story.title" id="title" required/>
</div>
<div>
<label for="firstName">Full Name</label>
<input type="text" ng-model="story.fullname" id="fullname" required/>
</div>
<div ng-repeat="story in items">
<label>Tag {{$index+1}}:</label>
<input type="text" ng-model="story.tag" required/>
</div> <a ng-click="add()">Add Tags</a>
<button id="save" class="btn btn-primary">Submit Story</button>
</form>
<div ng-repeat="test in items">
<label>Tag {{$index+1}}: {{test.tag}}</label>
</div>
</div>
</div>
The NoteController:
function NoteCtrl($scope) {
$scope.story = {};
$scope.items = [];
$scope.story.tag = $scope.items;
$scope.add = function () {
$scope.items.push({
inlineChecked: false,
tag: "",
questionPlaceholder: "foo",
text: ""
});
console.log($scope.story);
};
}

Resources