I've got a working angular select box:
<select class="form-control"
ng-model="selectedFeatureTypeFeature"
ng-options="FeatureTypeFeature.ProjectVersionFeatureID as
FeatureTypeFeature.Description for FeatureTypeFeature in FeatureTypeFeatures"></select>
Which I'm trying to modify the 'as' portion in the ng-options, to look like this:
<select class="form-control"
ng-model="selectedFeatureTypeFeature"
ng-options="FeatureTypeFeature.ProjectVersionFeatureID as
(FeatureTypeFeature.CustomDesciption != null? FeatureTypeFeature.CustomDescription : FeatureTypeFeature.Description) for FeatureTypeFeature in FeatureTypeFeatures"></select>
The difference is some FeatureTypeFeatures have a custom description and some do not. I want to display the custom description when its available, and the normal description when its not.
The problem is - it will only display the regular description whether there is custom description or not.
Logic like this really belongs in the controller, rather than the view.
An easy way to create a conditional list is to use the angular.forEach function in your controller. Here are the docs.
Without knowing the context of how your data is structured and your existing controller, I've created a generic solution which you can look through here: Plunker.
Basically you create a new $scope variable for the descriptions (and the id's) using the forEach iterator to conditionally push the description if the customDescription is empty:
$scope.descriptionList = [];
angular.forEach($scope.FeatureType, function(value, key) {
if (value.customDescription !== '')
$scope.descriptionList.push({ id:value.id, description:value.customDescription});
else
$scope.descriptionList.push({ id:value.id, description:value.description});
});
Then use this new $scope variable to populate your <select> form.
I hope this helps.
Solution: created a function in the controller, which returned the correct Description.
Html:
ng-options="FeatureTypeFeature.ProjectVersionFeatureID as (getFeatureTypeFeatureDescription(FeatureTypeFeature)) for FeatureTypeFeature in FeatureTypeFeatures"
Controller:
$scope.getFeatureTypeFeatureDescription = function (featureTypeFeature) {
return featureTypeFeature.CustomDescription || featureTypeFeature.Description;
}
Related
I have just started with Angular 4 and I need to develop a CRUD grid, where the user can add, edit or delete rows.
During my research I found this article where it shows how to create the grid and also the actions: Angular 4 Grid with CRUD operations.
Looking at his code, what called my attention was the way he is using the ng-template to toggle between edit/view mode.
<tr *ngFor="let emp of EMPLOYEES;let i=idx">
<ng-template [ngTemplateOutlet]="loadTemplate(emp)" [ngOutletContext]="{ $implicit: emp, idx: i }"></ng-template>
</tr>
On the article he uses template driven forms to edit the row. However, I was trying to change to reactive forms.
In my attempt to do that, I tried to replace the [(ngModel)] to formControlName and I got some errors. My first attempt I tried to add the [formGroup] at the beginning of the template html inside form element. But when I tried to run and edit the row, I got the following error:
Error: formControlName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class).
When I tried to move the [formGroup] inside the ng-template it works, however I was not able to bind the value to the fields and I had to set the values in the loadTemplate function:
loadTemplate(emp: Employee) {
if (this.selemp && this.selemp.id === emp.id) {
this.rForm.setValue({
id: emp.id,
name: emp.name
});
return this.editTemplate;
} else {
return this.readOnlyTemplate;
}
}
This works and show the values inside the fields in a read only mode :(
Here is the Plunker of what I have got so far.
How can I make a reactive form work with ng-template and how to set values to edit the entries?
Any help is appreciated! Thanks
Actually your form is not readonly, you are just constantly overwriting the input you are entering. Since you are having a method call in template (which is usually not a good idea), loadTemplate gets called whenever changes happen, which in it's turn means that
this.rForm.setValue({
id: emp.id,
name: emp.name
});
gets called over and over whenever you try and type anything. We can overcome this with instead setting the form values when you click to edit. Here we also store the index so that we can use it to set the modified values in the correct place in array, utilizing the index could perhaps be done in a smarter way, but this is a quick solution to achieve what we want.
editEmployee(emp: Employee) {
this.index = this.EMPLOYEES.indexOf(emp)
this.selemp = emp;
this.rForm.setValue({
id: emp.id,
name: emp.name
});
}
so when we click save, we use that index...
saveEmp(formValues) {
this.EMPLOYEES[this.index] = formValues;
this.selemp = null;
this.rForm.setValue({
id: '',
name: ''
});
}
Your plunker: https://plnkr.co/edit/6QyPmqsbUd6gzi2RhgPp?p=preview
BUT notice...
I would suggest you perhaps rethink this idea, having the method loadTemplate in template, will cause this method to fire way too much. You can see in the plunker, where we console log fired! whenever it is fired, so it is a lot! Depending on the case, this can cause serious performance issues, so keep that in mind :)
PS. Made some other changes to code for adding a new employee to work properly (not relevant to question)
I have to get the value of an input text with AngularJS but without using Controller.
How i can get this value?
I saw this posts but uses .controller
link post
You can use this code, with angular.element:
angular.element(document.querySelector('#your_input_tag_id')).val();
or, with simple jQuery:
$('#your_input_tag_id').val();
make your input a model and the value will always be available as the model
<input type="text" ng-model="myModelName">
and then your value will be available within the scope of your module as myModelName
console.log('value = ' + $scope.myModelName);
, if you are trying to get the value from somewhere other than the scope of the module or app then you are probably doing it wrong and not the angular way, it really is best to use a controller or link function even if it's the main app controller or link function, and you would be well placed to push back on any requirement not to use a controller (which sounds like a bad or misunderstood requirement).
Rather than querying the DOM for elements (which isn't very angular see How do I "think in AngularJS" if I have a jQuery background?) you should perform your DOM manipulation within your directive. The element is available to you in your link function.
So in your myDirective
return {
link: function (scope, element, attr) {
element.html('Hello world');
}
}
If you must perform the query outside of the directive then it would be possible to use querySelectorAll in modern browers
angular.element(document.querySelectorAll("[my-directive]"));
$('#your_input_tag_id').val();
however you would need to use jquery to support IE8 and backwards
angular.element($("[my-directive]"));
I have a dropdown that is defined using angular's ng-options syntax. I also have ng-model on the element and I am trying to get the selected model to output to the console. I have read a lot of different SO questions, but I just keep getting undefined. When I have the model defined in a service on rootScope then I get null.
Not sure what is going on, but it seems like the object isn't getting into the ng-model.
In the view:
<select ng-model="selected" ng-change="updateCategory()"
ng-options="conference.Name for conference in Adminconferences
| orderBy:['Name'] "></select>
In the controller:
$scope.updateCategory = function () {
console.log($scope.selected);
}
Update: I realized that maybe if i include what i am trying to do then maybe I can get better responses and have a better question.
This dropdown list is located in the header of my site. I want the user to be able to select which conference they want to manage. Based on that, I want all of the data in the site to be based on the conference's Id. I am not sure what the angular way of doing this is. I think i need to use rootScope and just reference it whenever i need the id for data calls. Is this acceptable?
I think you need to initialize $scope.selected in the controller before you use it inside function.
Initialize it like this:
$scope.selected = 0;
and then use it inside the function.
First, some background:
When using ui-select2, you have to supply an initSelection function in the select2 config object. If you don't, you'll get an error (but the functionality won't be affected. Everything will still work as expected).
To illustrate, see this plunkr. When you select an item from the dropdown menu, it'll work, but you'll get the following error:
Error: cannot call val() if initSelection() is not defined
Adding an empty function to initSelection fixes the error. You can uncomment it in the above plunkr to see that.
The problem:
When using ui-select2 in conjunction with ng-repeat, it just doesn't update the model.
Controller:
// for this demo, `users` is injected into the controller
$scope.users = users.slice(0, 2);
$scope.select2Config = {
placeholder: 'Select User...',
query: function ( options )
{
// `users` in this demo is injected into the controller.
// in the real world this would be an ajax request
options.callback({ results: users });
},
// Without initSelection, I get the above error.
// Regardless, the model isn't updated.
initSelection: angular.noop,
formatSelection: select2format,
formatResult: select2format,
};
function select2format ( user )
{
return user.first + ' ' + user.last;
}
View:
<ul>
<li ng-repeat="user in users">
<input type="text" ng-model="user" ui-select2="select2Config">
</li>
</ul>
When selecting an item from the dropdown list, the model isn't updated. If there's no initSelection in the config I get the above error, but adding it still doesn't update the model.
Here's a plunkr demonstrating the above.
The question:
How do I make ui-select2 update the model in an ng-repeat?
Try using inheritance:
http://plnkr.co/edit/jyJaYU4DQX1LROD6nQaw?p=preview
Also I you were calling "user in users" on the ng-repeat but then also setting the ng-model to "user". I am not sure why.
As to initSelection behavior, I do not have an answer.
edit
I updated the plunker. The ng-repeat directive creates a new scopes - true, but all of its children (or repeated items) are siblings. You had bound "user" (that was being defined/transcluded by ng-repeat) to the ng-model of each select (and expecting that the "users" array would be updated if you changed the model).
I believe ng-repeat is a one way binding top down
Therefor what I showed was correct but admittedly lazy. I bound both selects to the same model but I just as easily bound them to seperate properties on the "selected" object using $index.
Point is: if you want two way binding then write a new directive, but it is easier to do something similar to what I show.
PS: In practice I populate a "lookups" object that has some arrays for the select/pull-downs and use a seperate object called "user" that holds what the user has selected. This is pretty much pulled right out of the (older) documentation.
All, I am a newbie of Backbone. and I am trying to understand the Model of Backone. Especially how to define a Model. so far, I didn't saw a clear or formal way about how to define a Model for backbone.
For example Let's see the set method in help doc .
set
model.set(attributes, [options])
Set a hash of attributes (one or many) on the model.
Say we have some code like below . I think set method actually is assign a javascript object to the Model.
window.Employee = Backbone.Model.extend({
validate:function(attrs){
for(var key in attrs){
if(attrs[key] == ''){
return key + "can not be null";
}
if(key == 'age' && isNaN(attrs.age)){
return "age is numeric";
}
}
}
});
....
var attr = {}; // I can't not sure what is {} mean.
$('#emp-form input,#emp-form select').each(function(){
var input = $(this);//using jquery select input and select. and enumerate all of them.
attr[input.attr('name')] = input.val();//I am not sure what does it means
});
if(employee.set(attr)){
Employees.create(employee);
}
....
in this example ,I didn't saw the classical way which we can see in java class or c# class to define the class fields or methods. but only see a validate function .Is there anybody who can tell me more about it to help me understand? thanks.
To define a model in Backbone you have to extend the Backbone.Model object. For example if you'll like to create a new User model you could write something like this:
var User = Backbone.Model.extend({})
You can also overwrite some model methods to fill your needs. For example you can change the urlRoot attribute to tell the model where should he fetch the data.
Backbone models contain your data in the attributes attribute. You change those attributes by using the model set method and you can read the value stored in the model using the get method. So if you had some inputs where a user can enter information, for example creating a new user with his name and email and you have a form with a text input for both of them. You could do domething like this:
var user = new User;
user.set('name', $('#name').val());
user.set('email', $('#email').val());
attributes = {
name: user.get('name'),
email: user.get('email')
};
user.save(attributes);
There are a lot of ways to re-factor this code to make it look better but it help to see how you could use those methods. You should check the Backbone documentation to explore how they work a little bit more. Hope this helps!
PD: In my example I set an attribute a time, but you could also send a hash of attributes to set more values in one call.
The model in JS is basically a wrapper for data, with CRUD and simple validation functions. To work properly you need to make server functions to work with (ajax), I think this tutorial says it all http://backbonetutorials.com/what-is-a-model/. Instead of database the model works with your application server side.
If you have custom actions (not just add/edit/remove) on your data, you can manually "set()" data, use "onchange" event and refresh your view when needed. You can even attach "onchange" events only on specific fields and make custom functions in your view to handle each special field (for validation or display).
You can define fields at initialize and defaults value, but not custom functions (ofc you can do model.customFuntion() but I don't recommend it.
In order to make it more "clasical way" you need to use the other Backbone functions http://backbonejs.org/#Collection-Underscore-Methods and Backbone.Collection.