Complex "as label" for comprehension expression in angular - javascript

How can you set a complex 'as label' in a comprehension expression in angular?
This may be very simple, and I'm just not getting it, or it could be impossible, but I've looked everywhere and I can find no hints towards a solution. The only work around I've found is to pre-populate the 'as label' attribute of the object with the exact string you want before using it in the comprehension expression (which I'd like to avoid).
For example, I have an object like this:
$scope.projects = [{
"description": "Asset Management",
"code": "ASSET",
"fieldName": "Asset Evaluation Level"
},
{
"description": "Checklist",
"code": "CHECK",
"fieldName": "Checklist Scores"
},
{
"description": "IT Support",
"code": "IT",
"fieldName": "IT Support Ticket Number"
}]
I have a select with ng-options:
<select ng-model="jiraProject" class="form-control" ng-options="option as option.description for option in projects"></select>
I want the options 'as' label to appear in the select dropdown like this:
"Asset Management (ASSET)", "Checklist (CHECK)", "IT Support (IT)"
Maybe through syntax like this?:
option as {options.description (option.code)} for option in projects
Thanks for any and all feedback in advance!

Do this :
<select ng-model="jiraProject" class="form-control" ng-options="option as option | formatOption for option in projects"></select>
and this :
yourModule.filter('formatOption', [function(){
return function( option ){
return option.description + ' (' + option.code + ')';
};
}]);
Angularjs filters are so awesome :-)

Related

Allow for conditional .filter() and .map() in AngularJS on-change?

I have a problem where I am unable to edit the actual script of the page. That means I cannot add an AngularJS filter, directive, and so on. I am pretty limited, so I can only edit the HTML.
I want to be able to, based on the input from a dropdown, filter an existing list based on the selected property. This is relatively easy, and it can be done like this:
myArray.filter(x => x.Type == selectedType)
However, AngularJS throws up an error, because it won't allow me to use either .filter(function(){}) or .filter(x => x). At first I thought it was a problem with lambda, since AngularJS might not support that, but it turns out it's basically impossible to filter an array based on its properties.
This is my initial object:
[{
"id": "random",
"type": "1",
"name": "First tag"
},
{
"id": "random-2",
"type": "1",
"name": "Second tag"
},
{
"id": "random-3",
"type": "2",
"name": "Third tag"
}]
and if I do .filter(x => x.type = "2"), I should be able to get this list back:
[{
"id": "random-3",
"type": "2",
"name": "Third tag"
}]
Take a lookt at this Plunker: https://embed.plnkr.co/yudKIhsB2OQ9Phh0X1am
The "Filtered tags" in the HTML should show the filtered tags based on this condition (which works in normal JavaScript-language):
ng-change="vm.FilteredTags = vm.Tags.filter(x => x.type == vm.SelectedValue)"
You can filter out type property value which is matching vm.SelectedValue.
<p>Filtered tags: {{vm.Tags | filter: {type: vm.SelectedValue}: true }}</p>
Or using alias it would be way simpler, no need to have it on ng-change.
<div ng-repeat="vm.Tags | filter: {type: vm.SelectedValue}: true as FilteredTags">
... your sutff here...
<div>

Angular.js ng-repeat filter without knowing key

I am having troubles filtering my JSON file in the ng-repeat.
Here is the JSON data which is in my code is coming from Firebase
{
"850": {
"buttonText": "Button TST",
"description": "",
"documentNumber": "850",
"language": "fi",
"special": false,
"newOrder": 99000500850
},
"851": {
"buttonText": "eng ButtonTXT",
"description": "I would like to get this",
"documentNumber": "851",
"language": "en",
"special": false,
"newOrder": 99000500851
},
"852": {
"buttonText": "MORE FInnish button text",
"description": "Oh my",
"documentNumber": "852",
"language": "fi",
"special": false,
"newOrder": 99000500015
}
}
The JSON-data is stored into $ctrl.documentMatrixFirebase. Here is the Angular.js HTML. It is component which does what I want to except the filtering part.
<google-docs-card
layout="column"
ng-repeat="docButton in $ctrl.documentMatrixFirebase |
orderObjectBy:'newOrder' track by docButton.newOrder "
document-data="docButton"
subject="$ctrl.subject"
id="docnum_{{docButton.documentNumber}}"></google-docs-card>
Here is the code I tried to use for filtering without luck.
<google-docs-card
layout="column"
ng-repeat="docButton in $ctrl.documentMatrixFirebase |
filter:docButton.language:'en' |
orderObjectBy:'newOrder' track by docButton.newOrder "
document-data="docButton"
subject="$ctrl.subject"
id="docnum_{{docButton.documentNumber}}"></google-docs-card>
If possible, I would like to avoid adding custom filters for such a simple job.
Looks like that AngularJs to Array filter solved the problem:
https://github.com/petebacondarwin/angular-toArrayFilter
I installed the array filter according the instructions and used it in the HTML like this.
<google-docs-card
layout="column"
ng-repeat="docButton in $ctrl.documentMatrixFirebase
| toArray:false | filter: {language: 'en'}
| orderObjectBy:'newOrder' track by docButton.newOrder"
document-data="docButton"
subject="$ctrl.subject"
id="docnum_{{docButton.documentNumber}}"></google-docs-card>

AngularJS Select preselect not working

Preselection is not working in the select field even though the objects are equal:
<select ng-show="isEditMode(todo.id)" id="assignee" name="assignee"
ng-model="todo.assignee" required
ng-options="user.name for user in users">
</select>
todo.assignee contains a user object, which should match one from users.
It seems that Angular does not recognize that the User object from todo.assignee is contained in users. Can I perform this mapping manually?
The select is shown with no value selected. I can choose a user (from users) and save the record without any problem.
Controller
$scope.todos = Todo.query();
$scope.users = User.query();
Update
As requested in the comments. Structure of the given objects:
$scope.todos
[
{
"id": 157,
"description": "my description 0",
"deadline": 1392073200000,
"assignee": {
"id": 34,
"name": "User 1",
"email": "user1#hotmail.com"
},
"comment": "my comment 0",
"done": true
}
...
]
$scope.users
[
{
"id": 34,
"name": "User 1",
"email": "user1#hotmail.com"
},
{
"id": 35,
"name": "User 2",
"email": "xxc#gmail.com"
},
{
"id": 36,
"name": "User 3",
"email": "xx#hotmail.com"
}
]
The scope of the select comes from a repeat:
<tr ng-repeat="todo in todos | filter:query | filter:{assignee:queryAssignee} | filter:queryDone" ng-class="{danger: isDue(todo)}">
<td>
According to your description:
todo.assignee contains a user object
But your options' value are user.name strings, one object and one string will never be matched.
So, replace
ng-model="todo.assignee"
to
ng-model="todo.assignee.name"
UPDATE:
use ng-options="user.name as user.name for user in users"
Full Answer:
<select ng-show="isEditMode(todo.id)"
ng-model="todo.assignee.name" required
ng-options="user.name as user.name for user in users">
</select>
Plnkr:
http://plnkr.co/edit/A1XdMYmACNCr3OwBuFhk?p=preview
select as label for value in array
label: The result of this expression will be the label for element. The expression will most likely refer to the value variable (e.g. value.propertyName).
you can have refer here:
http://docs.angularjs.org/api/ng.directive:select
UPDATE2:
To fix the side effect, you can use option with separated value and display name
<select ng-model="todo.assignee" required>
<option ng-repeat="user in users" value="{{user}}" ng-selected="todo.assignee.name === user.name">
{{user.name}}
</option>
</select>
Plnkr:
http://plnkr.co/edit/6tzP9ZexnYUUfwAgti9b?p=preview
Explanation:
Before:
When you select one of option, it assign option value to model todo.assignee.name, so only change the name.
todo.assignee.name = "User 3" // like this
todo.assignee // didn't change the id & email
/* {"id": 34,
"name": "User 1",
"email": "user1#hotmail.com"} */
But, Now:
When you select one of option, it assign object value to model todo.assignee, so let what you want.
todo.assignee.name = {
"id": 36,
"name": "User 3",
"email": "user3#hotmail.com"
} // like this
todo.assignee // now change the whole value
/* {"id": 36,
"name": "User 3",
"email": "user3#hotmail.com"} */
Maybe it can be useful for someone else:
<select ng-show="isEditMode(todo.id)" id="assignee" name="assignee"
ng-model="todo.assignee" required
ng-options="user as user.name for user in users track by user.id">
</select>
The magic trick is in "track by user.id"
https://docs.angularjs.org/api/ng/directive/ngOptions

AngularJS - parsing JSON feed with namespace

New to angular, and it is awesome.
One thing I am having a brain fart on is parsing a JSON feed that contains namespaces:
Example from JSON feed:
"title": {
"label": "Fuse"
},
"im:name": {
"label": "John Doe"
},
"im:image": [ {
"label": "70x70",
"attributes": {
"height": "55"
}
}, {
"label": "80x80",
"attributes": {
"height": "60",
"im:link": "www.google.com"
}
}, {
"label": "90x90",
"attributes": {
"height": "170"m
"im:link": "www.yahoo.com"
}
}],
I can successfully parse items without namespaces fine like so:
<p ng-repeat="item in results.feed['entry']">
title: {{item.title['label']}}
</p>
But cannot get the items with namespaces to display using:
name: {{item.['im:name']['label']}}
OR
name: {{item.['im-name']['label']}}
OR
name: {{item.['im->name']['label']}}
Since being a newbie, I thought something like this would work:
<div xmlns:im="http://www.aol.com" id="im-app" im-app="im">
<p ng-repeat="item in results.feed['entry']">
…namespace code in here…
</p>
</div>
But that did not help.
Extra bonus question: What if a namespace contains attributes, that also contain namespaces?
Any help would greatly be appreciated.
Thanks!
Roc.
Although Craig answered the question,
This is also for reference for others:
If you want to target a specific key inside of an object set:
"im:image":[
{
"label":google",
"attributes":{
"height":"55"
}
},
{
"label":"yahoo",
"attributes":{
"height":"60"
}
},
{
"label":"aol",
"attributes":{
"height":"170"
}
}
{{item['im:image'][2]['label']}}
Will get the 3rd key in that set.
Thanks.
Get rid of the dot after item
Working example: http://jsfiddle.net/bonza_labs/Kc2uk/
You access the properties exactly the same way as straight javascript (because angular is basically eval()-ing the expression as javascript**). item.['foo'] is not valid javascript. You are correct in using square-bracket notation as my:name is not valid for dot-notation.
valid:
item.foo
item['foo']
with non-standard property names:
item['foo:bar']
item['foo-bar']
and in your case:
{{item['im:name']['label']}}
** or close enough for understanding this solution

Backbone? Can.js? Ghetto DIY? How should I work with this data?

I'm working on an application that lets our security dispatchers update a page that contains current road and campus conditions. The backend is a nodejs/express stack with and the data is a simple JSON structure that looks something like this:
{
"campus": {"condition": "open", "status": "normal"},
"roads": {"condition": "wet", "status": "alert"},
"adjacentroads": {"condition": "not applicable", "status": "warning"},
"transit": {"condition": "on schedule", "status": "normal"},
"classes": {"condition": "on schedule", "status": "normal"},
"exams": {"condition": "on schedule", "status": "normal"},
"announcements" : "The campus is currently under attack by a herd of wild velociraptors. It is recommended that you do not come to campus at this time. Busses are delayed.",
"sidebar": [
"<p>Constant traffic updates can be heard on radio station AM1234. Traffic updates also run every 10 minutes on AM5678 and AM901.</p>",
"<p>This report is also available at <strong>555-555-1234</strong> and will be updated whenever conditions change.</p>"
],
"links": [
{
"category": "Transportation Links",
"links": [
{
"url": "http://www.localtransit.whatever",
"text" : "Local Transit Agency"
},
{
"url": "http://m.localtransit.whatever",
"text" : "Local Transit Agency Mobile Site"
}
]
},
{
"category": "Weather Forecasts",
"links": [
{
"url": "http://weatheroffice.ec.gc.ca/canada_e.",
"text" : "Environment Canada"
},
{
"url": "http://www.theweathernetwork.com",
"text" : "The Weather Network"
}
]
},
{
"category": "Campus Notices & Conditions",
"links": [
{
"url": "http://www.foo.bar/security",
"text" : "Security Alerts & Traffic Notices"
},
{
"url": "http://foo.bar/athletics/whatever",
"text" : "Recreation & Athletics Conditions"
}
]
},
{
"category": "Wildlife Links",
"links": [
{
"url": "http://velociraptors.info",
"text" : "Velociraptor Encounters"
}
]
}
],
"lastupdated": 1333151930179
}
I'm wondering what the best way of working with this data on the client side would be (e.g. on the page that the dispatchers use to update the data). The page is a mix of selects (the campus, roads, etc conditions), TinyMCE textareas (announcements and sidebar) and text inputs (links). I'm open to changing this data structure if necessary but it seems to me to work well. I've been looking at Backbone, and also Can.JS but I'm not sure if either of those are suitable for this.
Some additional information:
there's no need to update an individual item in the data structure separatly; I plan on POSTing the entire structure when it's saved. That said...
there's actually two different views, one for the dispatchers and another for their supervisors. The dispatchers only have the ability to change the campus, roads, etc conditions through drop-downs and furthermore can only change the "condition" key; each possible condition has a default status assigned to it. Supervisors can override the default status, and have access to the announcements, sidebar and links keys. Maybe I do need to rethink the previous point about POSTing the whole thing at once?
the supervisors need to be able to add and remove links, as well as add and remove entire link categories. This means that DOM elements need to be added and removed, which is why I'm thinking of using something like Backbone or Can.js instead of just writing some ghetto solution that looks at all the form elements and builds the appropriate JSON to POST to the server.
Suggestions welcomed!
CanJS works great with nested data. can.Model is inheriting can.Observe which allows you to listen to any changes in the object structure.
If you include can.Observe.Delegate you have even more powerful event mechanism (example from the docs):
// create an observable
var observe = new can.Observe({
name : {
first : "Justin Meyer"
}
})
var handler;
//listen to changes on a property
observe.delegate("name.first","set",
handler = function(ev, newVal, oldVal, prop){
this //-> "Justin"
ev.currentTarget //-> observe
newVal //-> "Justin Meyer"
oldVal //-> "Justin"
prop //-> "name.first"
});
// change the property
observe.attr('name.first',"Justin")

Categories