Add dynamic model to newly created elements via directives in angularjs - javascript

Following is my PLNKR CODE which is working fine.
Problem - I need to add dynamic scope to these element so that I can grab the contact number + type.
I google the problem before asking but as I am new to directives in angular I am confused with the results, let me know what else I need to add to grab the result.
Following kind of result I am expecting -
contact: [
{number: 56432452, type: "Cell"},
{number: 67895644, type: "Work"},
{number: 78943245, type: "Cell"},
{number: 66793456, type: "Home"},
{number: 90546675, type: "Fax"},
];
Also, I need to use the same form in EDIT mode, let me know what are the extra things that I need to keep in mind while developing this functionality for the edit case.
Following is my directive code -
<div class="form-group">
<label class="col-sm-2 control-label">Contact Number<span class="asterisk">*</span></label>
<div class="col-sm-5">
<input type="text" class="form-control">
</div>
<div class="col-sm-2">
<select class="btn">
<option>Cell</option>
<option>Work</option>
<option>Home</option>
<option>Fax</option>
</select>
</div>
<div class="col-sm-1">
<img src="http://img.informer.com/icons/png/16/3225/3225535.png" class="remCls">
</div>
</div>
As you can see currently the select and input do not contain and ngModel. Let me know how do I introduce this to obtain the above mentioned result.

I'm not sure this is what you need but I think you could define your controller as:
myApp.controller("myCtrl", function($scope){
//Create and array of contacts in your model
$scope.contacts = [];
//Add a new contact to the model
$scope.addContact = function() {
var contacts = $scope.contacts;
contacts[contacts.length] = {};
}
//Remove a contact from the model based on its index
$scope.removeContact = function(index) {
$scope.contacts.splice(index, 1);
}
});
Then on your HTML, you leverage the Angular directives ng-repeat and ng-click:
<body ng-controller="myCtrl">
<button ng-click="addContact()"> Add Contact </button>
<div class="form-group" ng-repeat="contact in contacts">
<label>Contact Number</label>
<input type="text" ng-model="contact.contact">
<select ng-model="contact.type">
<option>Cell</option>
<option>Work</option>
<option>Home</option>
<option>Fax</option>
</select>
<button ng-click="removeContact($index)"> Remove Contact </button>
</div> <!-- Close Repeater -->
</body>
Here's your PLNKR link with the changes proposed:
http://plnkr.co/edit/VWCdXSnOsY18XoCKxO0t?p=preview

First of all I would like to thank ExpertSystem for suggesting me to think in Angular way. Then I would like to thank Foxandxss and medice from angular IRC for making the things right not by code but improving my concept and approach for angular.
This is the WORKING code, I came up with for the above problem.
Actually I don't need directive and managed things easily without it.
medice: directives are fine, but when you set up click events that
modify dom, it's gonna break
medice: angularjs can't bind directives properly
Following is my controller code -
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope){
$scope.cnctnum = [];
$scope.cncttype = [];
$scope.types = [
{name: "Cell", value: 1},
{name: "Work", value: 2},
{name: "Home", value: 3},
{name: "Fax", value: 4}
];
$scope.items = [];
var i =0;
$scope.addCnt = function(){
$scope.items.push(i);
i++;
};
$scope.remCl = function(index){
$scope.cnctnum.splice(index, 1);
$scope.cncttype.splice(index, 1);
$scope.items.splice(index, 1);
};
$scope.getval = function(){
console.log($scope.cnctnum);
console.log($scope.cncttype);
};
});

Related

Angularjs Error: [ngRepeat:dupes] in ng-options

Hello I'm making a code to study in angularjs and found the error.
Error: [ngRepeat:dupes]
http://errors.angularjs.org/1.6.4/ngRepeat/dupes?p0=cursostable%20in%20cursos%20%7C%20filter%3ApesquisaCurso&p1=object%3A3&p2=%7B%22codigo%22%3A45434%2C%22descricao%22%3A%22java%20web%22%2C%22datahorario%22%3A%22Segundas%20e%20Sextas%2C%2019hrs%22%2C%22professor%22%3A%7B%22codigo%22%3A1%2C%22nome%22%3A%22asasasasasa%22%2C%22email%22%3A%22asasasas%40hotmail.com%22%2C%22fone%22%3A%222323232323%22%7D%2C%22%24%24hashKey%22%3A%22object%3A3%22%7D
in console This error prevents me from entering new record
code below:
html
<div class="form-group">
<label for="professor" class="col-sm-1">Professor</label>
<div class="col-sm-10">
<select class="form-control" id="curso.professor"ng-model="curso.professor"
ng-options="professor.nome for professor in professores track by professor.codigo">
</select>
</div>
</div>
<button type="button" ng-click="salvar()" ng-disabled="!curso.codigo || !curso.descricao || !curso.datahorario || !curso.professor" class="btn btn-success">Cadastrar</button>
controller
cursoModulo.controller("cursoController", function($scope){
$scope.professores = [
{codigo: 1, nome: 'asasasasasa', email: 'asasasas#hotmail.com', fone:'2323232323'},
];
$scope.cursos = [
{codigo: 45434, descricao: 'java web', datahorario: 'Segundas e Sextas, 19hrs', professor: {codigo: 1, nome: 'asasasasasa', email: 'asasasas#hotmail.com', fone:'2323232323'}},
];
$scope.selecionaCurso = function(cursoSelecionado){
$scope.curso = cursoSelecionado;
}
$scope.limparCampo = function(){
$scope.curso = null;
}
$scope.salvar = function(){
$scope.cursos.push($scope.curso);
$scope.limparCampo();
}
$scope.excluir = function(){
$scope.cursos.splice($scope.cursos.indexOf($scope.curso),1);
$scope.limparCampo();
}
I suppose, new record has a such "codigo" that already presents in the "professores" list. Rememeber that all records in angular collections must have uniq field that you define in "track by" expression
It won't work if you are using angular version < 1.2.0
Change your version to (minimum of) 1.2 and it will work, since "track by" was introduced in that version.
Your code work on this fiddle (jsfiddle.net/JKBbV/1370) with angular 1.6.4
AngularJS does not allow duplicates in a ng-repeat directive.
That means whatever you are writing in track by should be unique so try track by $index instead of track by professor.codigo as said by rrd.
Working Plnkr
Source: click here!

how to watch an array property of array of array?

$scope.arr = [
[["TTT", 23],3],
[["PPP", 23],3],
[["KKK", 23],3]
];
I need to apply watch on arr[0][0][0] element of array.
Rendering arr[0][0][0], arr[1][0][0], arr[2][0][0] in text box using ng-model through ng-repeat for all arrays.
how to apply watch on ng-model variable as soon as i type something in text box?
I tried to apply watch on entire array arr but it didn't trigger below watch function
$scope.$watch($scope.arr, function (newVal, oldVal)
{
$log.log(newVal);
}
);
html:
<div ng-repeat="el in arr">
Name: <input type="text" ng-model = "el[0][0]" />
</div>
It seems the issue lies in the fact that a new scope is being generated for each iteration of ng-repeat. To get around this, you can attach a separate controller for each iteration, like explained here.
The simplest way I can think of to get around this without multiple controllers is to utilize the ng-change directive, like so:
JS:
$scope.getChanged = function(newValue) {
alert('getChanged(), new value: ' + newValue);
}
HTML:
<input type="text" ng-model="a[0][0]" ng-change="getChanged(a[0][0])" />
Here's a fiddle showing it in action.
If you only want to watch just those specific elements withing the array, you can use the Angular Scope's $watchGroup method to watch multiple expressions. Try out the example below.
angular.module("myApp", []).controller("TestCtrl", function($scope) {
$scope.arr = [
[
["TTT", 23], 3
],
[
["PPP", 23], 3
],
[
["KKK", 23], 3
]
];
$scope.$watchGroup($scope.arr.map((a, i) => "arr[" + i + "][0][0]"), function(newVals, oldVals) {
alert("Updated from " + oldVals + " to:" + newVals);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="TestCtrl">
<div ng-repeat="el in arr">
Name:
<input type="text" ng-model="el[0][0]" />
</div>
</div>
</body>

Create an Angularjs web form that duplicates but doesn't clone

I have "attempted" to build an Angularjs web form that duplicates the input fields upon clicking the add button and removes newly added fields upon clicking the "close button" which seems to work okay. Great, right!?
http://plnkr.co/edit/jUulJQ52m9QEZLkG086B
However, the duplicate forms created after clicking the add button are exact clones of each other or the original. So, when there are two forms on the screen and data entered into form 1, it is duplicated on form 2 and visa versa.
My question:
How do I continue down the path of having the ability
to duplicate the elements, really, within the "fieldset" element of the form, but without it being cloned?
Following are snippets of my HTML and AngularJs file. I have wracked my head on this for a while now and keep ending up in the same spot.....A fresh set of eyes and/or any suggestions would be great!
Thanks!
Index.html
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4" ng-controller="formCtrl">
<h1>Expense Form</h1>
<form class="form-horizontal" id="itvExpenseForm" name="ExpenseForm" ng-repeat="field in table.fields track by $index" novalidate>
<fieldset id="innerForm" ng-model="table.fields[$index]">
<legend>
<span>{{$index + 1}}.</span>
</legend>
<div class="form-group" ng-controller="quarterListCtrl">
<label for="ddlQuarters" class="col-sm-4 control-label">Year Quarter:</label>
<div class="col-sm-8">
<select class="form-control" name="Quarters" id="ddlQuarters" ng-model="formData.quarter">
<option value="">---Please select---</option>
<option ng-repeat="q in quarters">{{q.name}}</option>
</select>
</div>
</div>
<div class="form-group">
<label for="ddlDate" class="col-sm-4 control-label">Purchase Date:</label>
<div class="col-sm-8">
<input class="form-control" id="ddlDate" type="date" ng-model="formData.date" required>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button id="removeMore" aria-hidden="false" ng-click="removeForm($index)" ng-show="table.fields.length > 1">Close</button>
<button id="addMore" aria-hidden="true" ng-click="addNewForm()">Add</button>
</div>
</div>
</fieldset>
</form>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="submit" class="btn btn-success" ng-click="submitForm()">Submit</button>
</div>
</div>
</div>
<div class="col-md-4"></div>
</div>
</div>
</body>
App.JS
var app = angular.module('app', []);
app.controller('quarterListCtrl', function($scope, $http) {
$scope.quarters = quarters;
});
app.controller('accountsListCtrl', function($scope, $http) {
$scope.accounts = accounts;
});
app.controller('locationsListCtrl', function($scope, $http) {
$scope.locations = locations;
});
app.controller('formCtrl', function($scope, $http) {
$scope.formData = {};
var formCount = 1;
$scope.table = {
fields: []
};
// create first form on page load
$scope.table.fields.push(formCount);
// adds new field to table array which adds to page
$scope.addNewForm = function() {
formCount++;
$scope.table.fields.push(formCount);
};
// removes field from table array which removes form
$scope.removeForm = function(myIndex) {
if ($scope.table.fields.length > 1) {
$scope.table.fields.splice(myIndex, 1);
formCount;
}
};
});
var accounts = [{
'name': 'Account One',
'acct no': 123456789,
'id': 1
}, {
'name': 'Account Two',
'acct no': 987654321,
'id': 2
}];
var quarters = [{
'name': 'Fall',
'id': 1
}, {
'name': 'Winter',
'id': 2
}, {
'name': 'Spring',
'id': 3
}, {
'name': 'Summer',
'id': 4
}, ];
var locations = [{
'name': 'Here',
'id': 1
}, {
'name': 'There',
'id': 2
}, {
'name': 'Everywhere',
'id': 3
}];
As mentioned already, your formData is reference by all the elements in your array so a change in one element affects all of them.
To make things simpler, you don't need a formCount. Just have an array of formData and make use of angular.copy. So your controller becomes:
app.controller('formCtrl', function ($scope, $http) {
$scope.forms = [];
// create first form on page load
$scope.forms.push({});
// adds new field to table array which adds to page
$scope.addNewForm = function (formToCopy){
$scope.forms.push(angular.copy(formToCopy));
};
// removes field from table array which removes form
$scope.removeForm = function (formToRemove) {
var formIndex = $scope.forms.indexOf(formToRemove);
if (formIndex > -1) {
$scope.forms.splice(formIndex, 1);
}
};
});
See forked plunker for full markup changes but the main points are to change references from table.fields to just forms and pass the formData object to addNewForm and removeForm. So your ng-repeat becomes:
<form class="form-horizontal" name="ExpenseForm" ng-repeat="formData in forms track by $index" novalidate>
You can't use ng-model on a fieldset, so this doesn't do anything:
<fieldset id="innerForm" ng-model="table.fields[$index]">
Also, I would avoid using the id attribute on repeated elements otherwise there will be multiple elements with the same id on the page. You could opt for a dynamic id like id="innerForm-{{$index}}" but it's really not necessary in this case.
All your "ng-model" declarations link to a variable in the object "formData", e.g.
formData.quarter
formData.date
But you do only have one instance of formData on your scope. So there is one object $scope.formData and all duplicates of your form use that very same variable (formData.quarter) hence when you change quarter in your first form the quarter in the second form will change as well since its the very same variable.
What you need to do is to have a formData for every single created form.
For example you can have a variable
$scope.allFormDatas = [];
on your scope and in this array you will push a new instance of your old formData object, e.g.
$scope.addNewForm = function() {
formCount++;
$scope.table.fields.push(formCount);
var newFormData = {};
$scope.allFormDatas.push (newFormData);
};
now you will have to use that very instance of newFormData in your given forms, e.g.
<select class="form-control" name="Quarters" id="ddlQuarters" ng-model="allFormDatas[$index].quarter">
Furthermore you have to remove those formData objects from the array as well when you remove the form itself, of course.

Remove object from ng-repeat

I have a PhoneGap + Onsen UI + AngularJS app in the works, where I have a list in the view, where the items will be fetched from the controllers variable.
I want to be able to remove items from this list, by clicking on them.
The list looks like this:
<ons-list>
<ons-list-item modifier="tappable" class="item" ng-repeat="citem in completeditems" ng-click="delete(citem)">
<ons-row>
<ons-col>
<div class="titlediv">
<header>
<span class="item-title">{{citem.name}}</span>
</header>
</div>
<div class="item-dates">
<span class="item-start">{{citem.start}}</span>
</div>
</ons-col>
</ons-row>
</ons-list-item>
</ons-list>
The completeditems object in the $scope looks like this:
var completeditemname = "item" + i;
$scope.completeditems[completeditemname] = {
id : "ID",
name : "Name for it",
start: "Start date"
}
Tried the following method, but it didn't work out:
$scope.delete = function(item) {
var index = $scope.completeditems.indexOf(item);
$scope.completeditems.splice(index,1);
//$scope.completeditems.remove(item); //tried this aswell
$scope.$apply() //i need this to update the view
}
You do not need the $scope.$apply() invocation. As you are making alterations to scope variables the digest cycle will be triggered anyhow and you will be encountering an error because of this I believe.
UPDATED:: You're working with an actual object by the looks of it so I've updated the code in the plunker to help you out. It means altering the ng-repeat to use both key and value.
Here is a simple plunkr showing a basic example of what you are trying to do with a one liner in the delete function http://plnkr.co/edit/NtQD....
<body ng-app="myApp">
<div ng-controller="myController as ctrl">
<ul ng-repeat="(key, value) in ctrl.items track by key">
<li ng-click="ctrl.delete(key)">{{value}}</li>
</ul>
</div>
</body>
var myApp = angular.module('myApp', [])
.controller('myController', [
'$scope',
function($scope) {
var self = this;
self.items = {
item1: {
id: 1,
name: 'a'
},
item2: {
id: 2,
name: 'b'
},
item3: {
id: 3,
name: 'c'
}
};
self.delete = function(key) {
delete self.items[key];
};
}
]);
Hope that helps you out!
$scope.$apply() should only be used when changes are coming in from outside the Angular framework. Since your delete() function is being called from an ng-click, it is already being managed by Angular and calling $apply() will raise a "$digest is already in progress" error (check your browser console). Removing that call will most likely get your code working.

AngularJS - radio button not updating model

First steps in AngularJS. I'm facing a strange problem related to this, but the solution doesn't work to me, maybe I'm missing something (as I said, I'm a really n00b with angular).
I'm my HTML, I'm building some radio buttons like that:
<div ng-Controller="PageTwo" >
<h3>General Information > Knowledge About </h3>
<div>
<b>User</b>
<div>
<div ng-repeat="option in userOptions">
<input type="radio" name="userGroups" ng-model="$parent.userSelected" value="{{option.id}}" id="{{option.id}}">{{option.text}}
</div>
</div>
Selected thing: {{userSelected}}
</div>
</div>
This is my related Controller:
uxctModule.controller ('PageTwo', function ($scope, ModelData){
$scope.data = ModelData;
$scope.userOptions = [{text:'Option 1', id:0}, {text:'Option 2', id:1}, {text:'Option 3',id:2}, {text:'Option 4', id:3}];;
$scope.userSelected = ModelData.knowledgeAboutUser;
});
The model is the following object
uxctModule.factory ("ModelData", function () {
var data = {
// more code here
knowledgeAboutUser : 3,
}
return data
});
Now, the problem is that I'm logging in the console the ModelData object, and I've noticed that it's not updating when clicking the radio buttons.
I think the binding it's ok: I've tried to change the value in the Model, and the app selects the corresponding radio button.
Any help it's really appreciated, I'm stuck on this for hours
You can remove the intermediate variable $scope.userSelected:
<div ng-repeat="option in userOptions">
<input type="radio" name="userGroups" ng-model="data.knowledgeAboutUser" value="{{option.id}}" id="{{option.id}}">{{option.text}}
</div>
Selected thing: {{data.knowledgeAboutUser}}
It working fine
just change
$scope.userSelected
to
$scope.userSelected.selected
Working Code
script
var app = angular.module('app', []);
app.factory ("ModelData", function () {
var data = {
// more code here
knowledgeAboutUser : 2,
}
return data
});
app.controller("PageTwo", function ($scope, ModelData) {
$scope.userSelected = {};
$scope.userOptions = [{text:'Option 1', id:0}, {text:'Option 2', id:1}, {text:'Option 3',id:2}, {text:'Option 4', id:3}];;
$scope.userSelected.selected = ModelData.knowledgeAboutUser;
});
html
<div ng-app="app" ng-Controller="PageTwo">
<h3>General Information > Knowledge About </h3>
<div> <b>User</b>
<div>
<div ng-repeat="option in userOptions">
<input type="radio" name="userGroups" ng-model="userSelected.selected" value="{{option.id}}" id="{{option.id}}">{{option.text}}
</div>
</div>
{{userSelected.selected}}
</div>
</div>

Categories

Resources