Dynamic hidden fields values where model name is stored in database - angularjs

I have a requirement in angular js application where I need to dynamically create hidden variables. Name and value attribute for these hidden fields will be from database. But rather than storing actual value of hidden field in database name of model is stored in a database.
I have written a test function as follows. TempVars will be from database but for time being I have hard coded few values.
$rootScope.populate = function () {
$rootScope.models = {
MyModel: {}
};
$rootScope.models.MyModel.Client = [];
$rootScope.models.MyModel.Client.FirstName = 'FName';
$rootScope.models.MyModel.Client.LastName = 'LName';
$rootScope.TempVars = [
{"key":"var-FirstName","value":"{{models.MyModel.Client.FirstName}}"},
{ "key": "var-LastName", "value": "{{models.MyModel.Client.LastName}}" },
]
};
Following is my HTML code
<input type="hidden" ng-repeat="obj in TempVars" name="{{obj.key}}" value="{{obj.value}}" />
<input type="text" ng-repeat="obj in TempVars" name="{{obj.key}}" value="{{obj.value}}" />
<input type="hidden" name="test" value="{{models.MyModel.Client.FirstName}}" />
I am expecting that hidden filed value should have FName and LName in it. But rather it contains {{models.MyModel.Client.FirstName}} and {{models.MyModel.Client.LastName}} in it. Whereas variable name with name test has FName value stored in it.
Is is possible to achieve this in angularjs?

It won't work that way in angularjs but you will be able to do that through a custom directive and using NGModelController to $format and $parse the data.
Here are some links where you can get the idea about that :
https://egghead.io/lessons/angularjs-using-ngmodel-in-custom-directives
http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/

Related

Adding a custom type to angular-schema-form - datepicker

I'm trying to add a custom type to angular-schema-form for the ui-bootstrap datepicker.
I've followed the instructions, but my field isn't rendered when opening the form.
My module, loaded into the page:
angular.module('schemaForm-datepicker', ['schemaForm']).config(
[
'schemaFormProvider', 'schemaFormDecoratorsProvider', 'sfPathProvider',
function (schemaFormProvider, schemaFormDecoratorsProvider, sfPathProvider) {
var picker = function (name, schema, options) {
console.log(schema.type);
if (schema.type === 'date') {
console.log("found");
var f = schemaFormProvider.stdFormObj(name, schema, options);
f.key = options.path;
f.type = 'datepicker';
options.lookup[sfPathProvider.stringify(options.path)] = f;
return f;
}
};
schemaFormProvider.defaults.object.unshift(picker);
//Add to the bootstrap directive
schemaFormDecoratorsProvider.addMapping('bootstrapDecorator', 'datepicker',
'template/datepicker.html');
schemaFormDecoratorsProvider.createDirective('datepicker',
'template/datepicker.html');
}
]);
My template:
<div class="form-group" ng-class="{'has-error': hasError()}">
<label class="control-label" ng-show="showTitle()">{{form.title}}</label>
<input type="text"
class="form-control"
schema-validate="form"
ng-model="$$value$$"
placeholder="Date" />
<span class="help-block" sf-message="form.description"></span>
</div>
Schema Data:
{"type":"object","properties":{"FirstName":{"type":"string","title":"FirstName"},"LastName":{"type":"string","title":"LastName"},"CompanyName":{"type":"string","title":"CompanyName"},"EmailAddress":{"type":"string","title":"EmailAddress"},"JoinDate":{"type":"date","title":"JoinDate"}}}
Any ideas?
Assuming you are making changes date type.
You have to include your type of field in schema.
To implement add on, you have to
Add a new type of field
Add a new decorator
As it states in documentation, your new type should be second parameter to addMapping, then provide template and make sure you declare that type in your schema to display.
$scope.form =
[
{
key: "birthday",
type: "datepicker"
}
];
In your case, you have to change date to:
"JoinDate": {"type":"datepicker","title":"JoinDate"}.
note: datepicker already exists you can use that form type. but your custom impelementation will work as long as you dont include angular-schema-form-datepicker
documentation does have some information but it is confusing for first time.
https://github.com/json-schema-form/angular-schema-form/blob/master/docs/extending.md.
sorry, i cant comment so posting as answer.

ng-model - getting name and value of input box

I have an update function and a number of input boxes. Each input has an ng-blur attached to it so that the update function is called whenever the cursor leaves the box.
$scope.update = function(data) {
console.log(data); //outputs value in the textbox
//how can I output/access the key?
}
The input for name look like this:
<input type="text" ng-model="user.name" ng-blur="update(user.name)"/>
As I need to be able to post a JSON object in the form {"name" : "bob smith"} what's a good way of generating the "key" of the object bearing in mind that it will differ depending on the input box that's being used at the time?
EDIT ↓
I have made this jsfiddle to illustrate a way to do it more cleanly & that would scale more easily: http://jsfiddle.net/kuzyn/k5bh0fq4/5/
EDIT ↑
Why not simply pass a second string argument? It's not a fancy way to do it but it would work:
<input type="text" ng-model="user.name" ng-blur="update(user.name, 'name')"/>
And
$scope.update = function(data, key) {
console.log(key, data);
}
It might be a little more work but it is much more scalable. You could make use of the ng-form and naming your form inputs. By naming your form and inputs, you are creating a form reference on your scope via $scope[form-name]. Each named input within that form then sets an input reference via $scope[form-name][input-name].
I'm coding this in coffeescript (to preserve my sanity, sorry)
form
<form name="myForm">
<input name="name" ng-model="user.name" ng-blur="update(user)"/>
<input name="email" ng-model="user.email" ng-blur="update(user)"/>
<input name="other" ng-model="user.other" ng-blur="update(user)"/>
</form>
update & save func
# key is what changed in case you need to do something special on the put call to server
$scope.save = (data, key)->
# pseudo-code
$scope.update = (data)->
for name, input of $scope.myForm
if input?.$dirty
$scope.save data, name
break
docs - https://docs.angularjs.org/guide/forms
codepen - http://codepen.io/jusopi/pen/LGpVGM?editors=101

Post full form data to a service in Angular

I have a form that contains a lot of fields and I want to post all the form fields to a service using a post method. But I would like to send the whole form object and not to write one property by one. If I try to post the object that contains all my fields $scope.formData it also contains all the angular stuff inside like errors. What I need is a collection of field names and values. How can I achieve this with minimum coding?
Edit:
I ended up writing my own function:
function getAngularFormFields(form) {
var dictionary = { form: {} };
for (var key in form) {
if (form.hasOwnProperty(key) && !key.indexOf('$') == 0) {
dictionary.form[key] = form[key].$modelValue;
}
}
return dictionary;
}
Normally if you need to post a form you could just use the default method provided by your browser. This will send the form data, via POST, to your URL.
<form action="yourUrlHere" method="POST">
First name: <input type="text" name="fname">
Last name: <input type="text" name="lname">
<input type="submit" value="Submit">
</form>

Grouping results in ui-bootstrap typeahead [duplicate]

I am implementing typeahead using AngularUI-Bootstrap. I need to show the results grouped based on some values coming from the database. Here's a sample scenario
There are some users in the database, each user has a "Department". One user name can be available in multiple departments.
The end-user types in the names to search users from the database and retrieves the list in the typeahead list. Since one user name can belong to multiple departments, the requirement is to show the user names grouped by different departments. Something like this:
Then the user can select the desired user name and proceed.
As per the Typeahead documentation present here, I don't see any option to cater to my requirement.
I have tried the this workaround: Whenever the typeahead array is getting formed, I appended the user department to the array element:
$scope.fetchUsers = function(val) {
console.log("Entered fetchUsers function");
return $http.get("http://localhost:8080/TestWeb/users", {
params : {
username : val
}
}).then(function(res) {
console.log("Response:",res);
var users = [];
angular.forEach(res.data, function(item) {
users.push(item.UserName + " - " + item.UserDepartment);
});
console.log("users=",users);
return users;
});
};
This way, at least the end user sees the department. But when I select the record, the selected value is the full content of the array element. Below is sample screenshot to elaborate:
HTML
Users from local service
<pre>Model: {{userList | json}}</pre>
<input type="text" ng-model="userList" placeholder="Users loaded from local database"
typeahead="username for username in fetchUsers($viewValue)"
typeahead-loading="loadingUsers" class="form-control">
<i ng-show="loadingUsers" class="glyphicon glyphicon-refresh"></i>
User types in the string
User selects one record
I want to avoid the department (in this case, string - Desc 4 ) when user selects a record.
Is there any way I can achieve this grouping without any workaround? Or is there any way I can enhance my workaround?
I used to have a similar requirement and here is how I did it that time.
Example Plunker: http://plnkr.co/edit/zujdouvB4bz7tFX8HaNu?p=preview
The trick is to set the typeahead-template-url to a custom item template:
<input type="text" class="form-control" placeholder="Users loaded from local database"
ng-model="selectedUser"
typeahead="user as user.name for user in getUsers($viewValue)"
typeahead-template-url="typeahead-item.html" />
The item template, this represent each item in a dropdown:
<div class="typeahead-group-header" ng-if="match.model.firstInGroup">Desc {{match.model.group}}</div>
<a>
<span ng-bind-html="match.label | typeaheadHighlight:query"></span>
</a>
As you can see, there is an ng-if to show a group header if that item has a property firstInGroup set to true.
The firstInGroup properties are populated like this using lodashjs:
$scope.getUsers = function (search) {
var filtered = filterFilter(users, search);
var results = _(filtered)
.groupBy('group')
.map(function (g) {
g[0].firstInGroup = true; // the first item in each group
return g;
})
.flatten()
.value();
return results;
}
Hope this fit to your requirement too.
please see here http://plnkr.co/edit/DmoEWzAUHGEXuHILLPBp?p=preview
instead of creating new objects here:
angular.forEach(res.data, function(item) {
users.push(item.UserName + " - " + item.UserDepartment);
});
use create template :
<script type="text/ng-template" id="customTemplate.html">
<a> {{ match.model.name}} - department : {{match.model.dept}}</a>
</script>
and use it in your Typeahead directive
<input type="text" ng-model="selected"
typeahead="user.name as user for user in users | filter:$viewValue | limitTo:8" class="form-control"
typeahead-template-url="customTemplate.html">

how to set the default 'select' ng-model to an object?

I am trying to do a search engine interface with angular. The user selects some parameters in a form, click "search" and then it fills the url with the parameters using $location.search()
the search interface parameters which are used to build the form :
params = {
milestones: [ "a", "b", "c", "d", etc. ],
properties: [
{ "name": "name A", type: "text" },
{ "name": "name B", type: "checkbox" },
{ etc. }
]
}
inside the controller :
$scope.query = $location.search(); // get the parameters from the url
$scope.search = function (query) { // set the parameters to the url
$location.search(query);
};
and the html of the form
<select ng-model="query.milestone_name" ng-options="ms for ms in params.milestones">
<option value="">-select milestone-</option>
</select>
<select ng-model="property" ng-options="prop.name for prop in params.properties" ng-change="query.property_name=property.name">
<!-- if the object 'property' was passed in the url, it would look like this `%5Bobject%20Object%5D`, so its 'name' parameter is converted to a string -->
<option value="">-select property-</option>
</select>
<span ng-switch="property.type">
<label ng-switch-when="text">{{query.property_name}}: <input type="text" ng-model="query.property_value"></label>
<label ng-switch-when="checkbox">{{query.property_name}}: <input type="checkbox" ng-model="query.property_value"></label>
</span>
<button ng-click="search(query)">search</button>
and somewhere else in the page is the list of results.
the user can also access to a search result page with an url like this:
http://myapp.com/search?milestone_name=a&property_name=name%20A
almost everything works fine : the list of results is displayed, the "milestone" parameter is pre-selected with the correct value in the select component, but not the "property" parameter because it's not a string, it's an object.
how can i set the default value (ng-model) of the select component to an object ?
or any other idea on how i should do this ?
When using an array of objects for the select to iterate over, the ng-options directive needs to have an attribute of the object to match against (and differentiate between arrays)
Use the track by section of the directive declaration eg
<select ng-model="property" ng-options="prop.name for prop in params.properties track by prop.name" ng-change="query.property_name=property.name">
<!-- if the object 'property' was passed in the url, it would look like this `%5Bobject%20Object%5D`, so its 'name' parameter is converted to a string -->
<option value="">-select property-</option>
</select>
You can use this form of comprehension expression in ngOptions: label group by group for value in array. Html drop down list will display only name of selected object. Model will contain whole selected object. You can set selected object from controller.
<select ng-model="property"
ng-options="prop as prop.name for prop in params.properties">
</select>
Check this plnkr example.
ng-options is generating some options to be used with ng-model. In your syntax (prop.name for prop in params.properties) you've told it to bind to the object found in the array (as oppose to a property on it - which is what you want to do) and use its name property as the value to display. So when you try and set the ng-model to be an object that's not in the ng-options array nothing happens - I'm guessing because it's using reference/shallow equality and not deep equality. So what you should do is either:
Convert the ng-options object to be an array of strings.
Use a syntax that involves keys, such as:
prop.name as prop.name for prop in params.properties
http://jsfiddle.net/C5ENK/
If that doesn't suit your needs let me know why and I'll see if I can help further.
i found a kind of solution…
when selecting a property, it saves the index of this object and then when the page loads, it sets the ng-model of the select to the value of this index. it uses this : example for setting the index and this example for getting the value of this index in the array of objects.

Resources