Below code show binding for a List emails but I am having trouble binding the newly added emails to the $scope.emails (does not contain the new email user added). Any idea?
// emails is a List on server side
// email is a string
so i bind ng-model= email but
but doing the below does not work
$scope.contactInformation.Emails.push(email); --> complains about duplicates
<div ng-repeat="email in emails">
<div class="form-group">
<label for="email">Email</label>
<div class="input-group input-group-sm input-group-minimal">
<span class="input-group-addon">
<i class="linecons-mail"></i>
</span>
<input type="text" class="form-control" ng-model="email" />
</div>
<button class="btn btn-primary" ng-show="$last" ng-click="AddEmail()">Add Email</button>
Controller.js
// modelParams.ContactInformation.Emails = new List(string)() when retrieved on server side
$scope.emails = modelParams.ContactInformation.Emails;
$scope.AddEmail = function () {
$scope.contactInformation.Emails.push({ email: null });
};
I'm amending the answer to avoid confusion... Here's is how it should be done - fill in the blanks to fit it for your scenario.
controller.js
// assuming emails is an array of strings (whether defined locally or from a server)
$scope.emails = ["email1", "email2", ...];
$scope.addEmail = function(){
$scope.emails.push(""); // push an empty array as new not-yet-set email
}
The HTML is largely correct. I would have moved the "add" button to outside of the ng-repeat div instead of relying on $last:
<div ng-repeat="email in emails track by $index">
<input type="text" ng-model="email" />
</div>
<button ng-click="addEmail()">Add Email</button>
EDIT:
The example above would, actually, not work because the ng-model within ng-repeat binds to a primitive (string) email.
There are 2 ways to fix:
approach 1
Make an array of objects. If you get an array of strings from the server, you'd need to convert to an array of objects, like so:
$scope.emails = [];
angular.forEach(arrayOfEmailStrings, function(v, k){ $scope.emails.push({value: v}); });
And access like so:
<input type="text" ng-model="email.value" />
approach 2
Use the $index property:
<input type="text" ng-model="emails[$index]" />
Related
In my Project i Got a Issue like.I need to bind the user hobbies in the text field.if the user comes with a single hobby he can directly enter the hobby that he has. but when he had multiple then he had to click add multiple hobbies button.that working fine when i am displaying input fields dynamically using directives.but the issue is the value that coming from ng-model for that input field is binding to all input fields.
Here is my code.
Thanks in advance!
these are the images
this is how i am getting
this is what i need
In HTML
<div>
<div id="showHobbyfield"></div>
<input type="number" class="form-control" placeholder="ADD HOBBIES"
ng-click="addHoby()">
</div>
In controller
$scope.addHoby= function(){
var compiledeHTML = $compile("<div my-hobby></div>")($scope);
$("#showHobbyfield").append(compiledeHTML);
};
$scope.addUser = function(){
$scope.Users= [];
var obj = {
userhobby : $scope.user.morehobies
};
$scope.Users.push(obj);
menuStorage.put($scope.Users);
//menustorage is service to store user in localStorage.
In directive
'use strict';
angular.module('myApp')
.directive('myHobby', function() {
return {
scope : false,
templateUrl: 'views/my-hobby.html'
};
});
this is template: my-hobby.html
<div class="input-group">
<input type="text" ng-model="user.morehobies" class="form-control" placeceholder="type your hobbies here">
<div class="close-icon">
<span class="glyphicon glyphicon-remove" style="padding-left: 6px;"> </span>
</div>
</div>
For this i would suggest some other way if its ok with you.
If your hobbies is coming in array, like
user.morehobies = ['Reading', 'Writing']
or create array for storing hobbies.
then inside directive you can pass that object in directive.
I will use ng-repeat inside directive.
<div class="input-group" ng-repeat="h in hobies">
<input type="text" ng-model="h" class="form-control" placeceholder="type your hobbies here">
<div class="close-icon">
<span class="glyphicon glyphicon-remove" style="padding-left: 6px;"> </span>
</div>
</div>
so whenever user clicks on "Add hobbies" then we can add empty string in hobbies object in directive.
and whenever user clicks on remove you can remove that item from array.
I create a form dynamically in the view by iterating through an object that has the different questions to be asked to the user. One of the attributes of every question is formFieldName which is a a random string I use to give each form field a different name.
<form name="includedForm.newRequestForm" class="form-horizontal" role="form" novalidate>
<div ng-if="message.question.attributes.structure.type == 'object'">
<div ng-repeat="(index,objField) in message.question.attributes.structure.properties">
<div ng-if="objField.type == 'array'" class="form-group" show-errors>
<label for="{{objField.formFieldName}}" class="control-label col-sm-6">{{objField.title}}
<br /><i><small>{{objField.description}}</small></i></label>
<div class="col-sm-6">
<select class="form-control" name="{{objField.formFieldName}}" multiple ng-model="objField.userValue" ng-required="objField.required">
<option ng-repeat="option in objField.items.enum" value="{{option}}">{{option}}</option>
</select>
</div>
</div>
<div ng-if="objField.type == 'boolean'" class="form-group" show-errors>
<label for="{{objField.formFieldName}}" class="control-label col-sm-6">{{objField.title}}</label>
<div class="col-sm-6">
<input class="form-control" name="{{objField.formFieldName}}" ng-model="objField.userValue" type="checkbox" ng-value="option" ng-checked="message.question.attributes" />
</div>
</div>
</div>
</div>
<div class="col-sm-12">
<button ng-click="markAsDone(message)" class="btn btn-primary">Done</button>
</div>
<form>
In the controller I'm able to get the formFieldName attribute but I can't figure out how to use it to do the validation.
var MarkAsDone = function(message) {
$scope.includedForm = {};
var formField = message.question.attributes.formFieldName;
if ($scope.includedForm.newRequestForm.{{formField}}.$valid){
//submit the form
}
}
to answer you question:
first, {{}} is === $scope so you don't use that anywhere other than HTML. You use $scope in your JS and {{}} in HTML which creates a pipe (2-way binding) so that $scope.variable.property has bidirectional binding to {{variable.property }} in HTML.
$scope.includeForm.email === {{ includeForm.email }} === ng-model="includeForm.email" === ng-bind="includeForm.email"
if you set anyone of those all are set so if you set $scope it will show up in HTML and obviously as user input gets captured it is already in $scope ... all connected
when attempting to get the value from HTML back into JS you would need create and set a $scope i.e so if you create $scope.dataModel.dataProperty and use that in ng-model=dataModel.dataProperty (example) you again have two way binding ... you don't need to do anything as angular is taking care of the data pipeline. So if you want to extract the value to var, which is probably a waste as the $scope is already set as soon as the user checks the box
var formField = $scope.dataModel.dataProperty;
// but like I said no need as $scope.dataModel.dataProperty; is your var
In JS if you want to use a dynamic property as an object property key you would place the dynamic value in [] e.g.
$scope.variable[dynamicProperty].method;
// you can set a static property as a key with dot notation i.e.
$scope.variable.staticProperty = val;
Hope that helps
I have a Service who can add by a user. It can be one or more.
I have a button to add a Service
<button type="button" class="btn btn-success" ng-click="addService()">
<span class=" glyphicon glyphicon-plus">
</span>Add Service
</button>
When i click Add Service angular should creare a new Service in a list of services.
I have two textareas for Informations of the Service.
<label for="usr">Name:</label>
<input type="text" class="form-control" id="name"></br>
<label for="usr">Service:</label>
<input type="text" class="form-control" id="service"></br>
When i click on the Add Service Button a knew Service Button should be generated with this textareas.
How can generate that and add the new Service to a list of services?
$scope.services = [];
$scope.addService = function() {
var newService = {
name : 'a name',
service : 'a service'
};
$scope.services.push(newService);
}
and the HTML
<div ng-repeat="service in services"><label for="usr">Name:</label>
<input type="text" class="form-control" value="{service.name}"></br>
<label for="usr">Service:</label>
<input type="text" class="form-control" value="{service.service}"></br></div>
You would use ng-model which will take care of 2 way binding fields to scope object
<label for="usr">Name:</label>
<input ng-model="newService.name"></br>
<label for="usr">Service:</label>
<input ng-model="newService.service"></br>
Then in controller
$scope.addService = function() {
// copy and push newService object to array
$scope.services.push(angular.copy($scope.newService));
// reset newService object to clear fields
$scope.newService = {};
}
If you use a form for this you can use angular validation and move the ng-click to ng-submit on the form. ng-submit won't trigger if validation fails
I am having difficulty with a javascript that I need some help with. I have a form which sends to a php the exact amount of inputs to be filled, now I want to create a preview using jQuery/javascript but how can I catch all the fields dynamically.
Here is a portion of my form for reference:
<td>
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-pencil"></i></span>
<input class="form-control" id="task" type="text" name="task" placeholder="Task Title">
</div>
</td>
<td>
<div class="input-group">
<span class="input-group-addon">
<i class="fa fa-pencil"></i>
</span>
<input class="form-control" id="description" type="text" name="description" placeholder="Task Description">
</div>
</td>
So, I added in PHP the name field + the number, this way I can get different names ie: task1, task2,...etc.
Now what I need to do is get the values using jQuery/javascript.
My thoughts so far is to declare the var (variable) inside a for() (loop)
var task = $('input[name=task]').val();
How can I get all values task1, task2. No one knows how many task fields the user will submit so I need to get the number of fields
Any help direction so I can figure this out
First of all, you don't need to give your input fields names like task1, task2, etc to distinguish among them on the server-side i.e on the PHP. You just need to give all of them a name attribute value like tasks[] And notice the brackets [] so you may have something like the following:
<input class="form-control" id="tasks[]" type="text" name="tasks[]" placeholder="Task Title">
...
<input class="form-control" id="tasks[]" type="text" name="tasks[]" placeholder="Task Title">
Like that automatically values in those fields will be posted as an array to the PHP and it is going to be received like the following in PHP script:
$tasks = $_POST['tasks'];
foreach ($tasks as $task){
echo $task;
}
Second By this way you will easily able to collect your inputs data using Javascript inorder to generate the preview by using getElementsByName method as follows:
function preview(){
output = "";
tasks = document.getElementsByName('tasks[]');
for (i=0; i < tasks.length; i++){
output += "<b>Title</b>: "+tasks[i].value+"<hr />";
}
panel = document.getElementById('panel');
panel.innerHTML = output;
}
Of course you can expand this solution to any number of fields in your form such as descriptions[].
A javascript DEMO: http://jsbin.com/kiyisi/1/
Using the Attribute Starts With Selector [name^="value"] and jQuery.each()
var tasks = $('input[name^=task]').val();
$.each(tasks,function(index, value){
//do something with the value
alert($(this).val());
});
edit
var tasks = $('input[name^=task]');
$.each(tasks,function(index, value){
//do something with the value
$('#Preview').append($(this).val());
});
Q: now I want to create a preview using jquery/javascript but how can I catch all the fields dinamically:
If you give them a class, you can get all fields with each:
$(".className").each(function() {
do something
Next, "catch" all fields... I'm assuming you may want the values of these fields too? Check this example for details, here is a snippet which loads the key:value pairs (form field name : value of field) into a map:
var map = {};
$(".activeInput").each(function() {
map[$(this).attr("name")] = $(this).val();
});
Print all values inside div (Here, I'm assuming you're talking about children values of div):
<div>
<span>Hi</span>
<span>Hello</span>
<span>Hi again</span>
</div>
$("div").children().each(function () {
console.log($(this).text());
});
OR
$("div span").each(function () {
console.log($(this).text());
});
I'm trying to do some very simple validation using the knockout validation plugin. I want to validate if at least one text field has text and at least one checkbox is checked. All bindings work correctly and knockout itself is awesome so far. I've tested native validation rules and they work with messaging. I just can't get the validation to work for these 2 rules.
I realize I can check for empty values very easily with jQuery but I would really like to utilize knockout.
The model (without validation because I haven't found anything that works yet):
var SearchForm = function(collections) {
// main search fields
this.fullRecord = ko.observable();
this.title = ko.observable();
this.author = ko.observable();
// collections to search
var sources = [];
$.each(collections, function(index,collection) {
sources.push(new Source(collection));
});
this.sources = ko.observableArray(sources);
// Error handling vars
this.errors = ko.validation.group(this);
};
var Source = function(collection) {
$.extend(this,collection);
this.id = "collection-"+this.code;
this.selected = ko.observable(true);
};
Here I'm just creating a list of source objects from collection data that comes from the server. That data is irrelevant since I'm only concerned with the observable 'selected' property.
The markup:
<div id="advanced-controls" class="row">
<div class="col-sm-8">
<fieldset id="search-fields">
<div class="form-group">
<label for="fullrecord" class="control-label">Keywords:</label>
<input type="text" id="fullrecord" class="form-control" name="fullrecord" placeholder="Full Record Search" data-bind="value:fullRecord" />
</div>
<div class="form-group">
<label for="title" class="control-label">Title:</label>
<input type="text" id="title" name="title" class="form-control" data-bind="value:title"/>
</div>
<div class="form-group">
<label for="author" class="control-label">Author:</label>
<input type="text" id="author" name="author" class="form-control" data-bind="value:author"/>
</div>
<div class="form-group">
<button id="advanced-search-submit" class="btn btn-primary" data-bind="click:search">Search</button>
<button id="advanced-search-reset" class="btn" data-bind="click: clear">Clear All</button>
</div>
</fieldset>
</div>
<div class="col-sm-4">
<fieldset data-bind="foreach: sources">
<div class="form-group">
<input type="checkbox" name="collections" data-bind="attr:{ id:id, value:code }, checked:selected, click: $parent.clearRequiredSourceError ">
<label data-bind="attr:{ for:id }, text: name"></label>
</div>
</fieldset>
</div>
</div>
In the validation function before submitting:
// If there's any knockout validation errors
if (model.errors().length > 0) {
model.errors.showAllMessages();
isValid = false;
}
I've tried setting a custom validation extension on the observable array of sources like this:
this.sources = ko.observableArray(sources).extend({
validation: {
validator : function (sources) {
var anySelected = false;
$(sources).each(function(){
anySelected = this.selected();
});
return anySelected;
},
message: 'At least one source is required to search.'
}
});
But that doesn't fire when the checkboxes are clicked, only when the array is changed ~ push, pop, etc. Yes I have the config set correctly:
ko.validation.configure({
grouping: {
deep: true,
observable: true
}
});
This seems like it should be very simple to achieve. Maybe my brain is just fried from diving into the whole knockout world this week. Any suggestions are greatly appreciated. Thanks in advance!
Forgive me for not reading your entire question, as it is very long, but I am curious if you need Knockout validation for this or if you are looking for something like this -
var selectedOption = ko.observable();
var selectionsOk = ko.computed(function () {
((!!field1()|| !!field1()|| !!field1())&&!!selectedOption())
});
Where selectedOption is a list of radio buttons, and once one is selected returns the value, and you could either use an observableArray to contain each of your fields so it is dynamic or you list the fields out and make sure that at least one of them has a value. The !! will evaluate your observable as true or false, true would be returned unless the observables' value was null, undefined, '', or false
The selectionOk computed could be used to prevent clicking some button to proceed or inversely for displaying an error message until the conditions are met.