I'm trying to show all lists and the tasks associated with each list. In my controller I have:
$http.get('api/list/').success(function (data) {
$scope.lists = data;
$scope.tasks = data[0].Task;
});
This works for the first item but of course data[0].Task needs to be dynamic. The problem I'm having is that this is being called once for each list. I tried using a variable but it gets reset to it's original value. I've also tried using a callback but no luck. I'm not sure what I'm overlooking or if I'm going about it all wrong.
Your best bet is to wrap the http.get in a factory and let it return new representations of your Lists that have the tasks in them. This way you get new references and it won't overwrite your existing objects. Essentially, you want the http.get to return new List objects in its success resolution.
After that, the controller gets the promise resolution, takes the new list object, and binds it into something thats on the scope. This will filter through to the rest of the page and let you preserve existing lists/tasks for the life of the page.
Your GET api/list/ request you probably return something like this:
[
{
"id": 1,
"name": "List #1",
"tasks": [
{
"id": 1,
"name": "Task #1 on List #1"
},
{
"id": 2,
"name": "Task #2 on List #1"
},
{
"id": 3,
"name": "Task #3 on List #1"
}
]
},
{
"id": 2,
"name": "List #2",
"tasks": [
{
"id": 1,
"name": "Task #1 on List #2"
},
{
"id": 2,
"name": "Task #2 on List #2"
},
{
"id": 3,
"name": "Task #3 on List #2"
}
]
}
]
This is assuming that you always want to return the associated tasks in an api/list/ command.
You then only need to call this once every time you want to refresh all lists and all tasks.
You should have a single controller which is bound to a view, in which your $http.get is called. It should set $scope.lists = data on success.
In your view you simply need two nested ng-repeat tags. For example, you could use unordered lists:
<div ng-controller="ListsController">
<ul>
<li ng-repeat="list in lists">
<ul>
<li ng-repeat="task in list.tasks">
</li>
</ul>
</li>
</ul>
</div>
I haven't used angular but I'm pretty sure this is all you need to do. A single AJAX call will populate a <li> element for each list, with nested <li> elements for each task belonging to that list.
If each list has a task and you want a list of them you can do this:
$scope.tasks = data.map(function(obj){return obj.task;})
map creates an array based on what the function returns for each list.
Related
I'm currently having an issue accessing nested objects that are referred to through numbers. I made a service call to retrieve a JSON object, and then mapped each field to another object. I'll be using this object to display each field in the HTML.
My problem is occurring when I reach the nested objects. Here's an example :
{
"name": {
"title": "mr",
"first": "something",
"last": "something"
},
"role": "something",
"projects": {
"0": {
"title": "something",
"account": "something",
"steps": {
"total": 30,
"completed": 28
},
"dueDate": "2021-07-19 09:00:00",
"status": "fine"
},
"1": {
"title": "something",
"account": "something",
"steps": {
"total": 10,
"completed": 5
},
"dueDate": "2021-07-20 09:00:00",
"status": "fine"
},
}
}
The projects field gets tricky when trying to display all projects in the HTML. At the moment, I've created a person variable initialized to an empty array, and I add all of the fields from t he subscription to it. To solve this problem, I figured I should create a separate variable such as projects: any = []; and then set it to a new field in the person variable. Then iterate through it using an *ngFor, and display every project. Something like this
<li *ngFor="let project of person.projects">
{{ project }}
</li>
However that approach still doesn't reach the nested fields. How do I access the numbered objects here, and generally iterate through all of the nested fields?
Any advice will be very helpful. Thank you in advance.
I think you are looking for the KeyValuePipe
You would use it like this:
<li *ngFor="let item of person.projects | keyvalue">
{{ item.value }}
</li>
But based on your comment on doing this for more nested values, it might be worth flattening the data a bit in the component to simplify the template logic.
Im very new to JS and OJET. I'm using oracle jet to create a form. I need to create two select fields, the firts displays a client's name and the next one must change is values with the selected client's team members.
I have a JSON File with this format:
{
"clients": [
{
"id": "C01",
"name": "Client 1",
"manager": "Manager 1",
"team": [
{
"id": "C1MEM1",
"name": "member 1"
},
{
"id": "C1MEM2",
"name": "member 2"
},
{
"id": "C1MEM3",
"name": "member 3"
},
{
"id": "C1MEM4",
"name": "Member 4"
}
]
},
{
"id": "C02",
"name": "Client 2",
"manager": "Manager 2",
"team": [
{
"id": "C2MEM1",
"name": "member 1"
},
{
"id": "C2MEM2",
"name": "member 2"
},
{
"id": "C2MEM3",
"name": "member 3"
},
{
"id": "C2MEM4",
"name": "member 4"
}
]
}
I managed to create a select field with the clients name:
self.clientsListVal = ko.observableArray(['C01']);
self.clientsList = ko.observableArray();
$.getJSON("http://localhost:8000/js/json/clients.json").
then(function(data){
$.each(data["clients"],function(){
self.clientsList.push({
value: this.id,
label: this.name
});
});
});
Then I tried to get the next select fields this way, but it doesn't work :( :
self.memberList = ko.observableArray();
$.getJSON("http://localhost:8000/js/json/clients.json").
then(function(data){
$.each(data["clients"],function(){
if (this.id === self.clientsListVal ) {
$.each(this["team"], function(){
self.memberList.push({
value: this.id,
label: this.name
});
});
}
});
});
This is the HTML im using:
<div class="oj-applayout-content">
<div role="main" class="oj-hybrid-applayout-content">
<div class="oj-hybrid-padding">
<h3>Dashboard Content Area</h3>
<div>
<label for="clients">Clients</label>
<select id="clients"
data-bind="ojComponent:
{component: 'ojSelect',
options: clientsList,
value: clientsListVal,
rootAttributes: {style:'max-width:20em'}}">
</select>
<label for="select-value">Current selected value is</label>
<span id="select-value" data-bind="text: clientsListVal"></span>
<label for="members">Members</label>
<select id="members"
data-bind="ojComponent: {component: 'ojSelect',
options: memberList,
value: memberListVal,
rootAttributes: {style:'max-width:20em'}}">
</select>
</div>
</div>
</div>
Any help or hint? thank you!.
EDIT:
I think the problem is that self.clientsListVal is returning a function not the current selected value. I added console.log(self.clientsListVal) to the view model to see the current value.
If I change self.clientsListVal for a string:
if(this.id === 'C01'){}
I get the members of the client "C01".
I tried changing self.clientsListVal to $('#clients').val(), this is the id of the select input and i get undefined in the console.log.
How can I get the select field string value inside the viewmodel?
In Knockout, observables are functions -- so when you ask for the observable directly, like self.clientsListVal, you get the function definition. To get the underlying value, call the observable like a function: self.clientsListVal().
So your test becomes if (this.id === self.clientsListVal() ) {
Now you have another problem -- the observable holds an array, not an ID. The array may have a single ID element in it, but you have to reach into the array to get it.
Since you didn't show us how a value gets into clientsListVal, it's hard to say what you need to do. Is it bound to an input field where the user specifies a value? Is it populated from a data call? either way, do you ever need to have more than one ID in clientsListVal? If you only need to hold one ID at a time, change clientsListVal from an observableArray to a simple observable and your test will work.
If clientsListVal can hold multiple values, you'll need to loop over them. There are various ways to do this. You can get the underlying array by assigning the value of the observableArray to a variable: var clients = clientsListVal(). clients now holds the array, and you can use jQuery's $.each, the native Array.each, or some other way to loop over or map the array. Or you can use Knockout's built-in array utilities, like arrayForEach
if you don't want to change to a regular observable but expect the array to only have a single element, you can get at it like clientsListVal()[0] -- that's the 0th (first) element of the array. Watch out for empty arrays, tho.
It should be noted that I'm very new to Angular.
I have the following JSON I get from Django Rest Framework:
api/movie/1
{
"id": 1,
"name": "Mr & Mrs Smith",
"actors": [
1,
2,
]
}
api/actor/1
{
"id": 1,
"name": "Angelina Jolie",
}
api/actor/2
{
"id": 2,
"name": "Brad Pitt",
}
I made a movie detail page following the Angular tutorial, using $resource.
This is the movie-detail.component.js
angular.
module('movieDetail').
component('movieDetail', {
templateUrl: 'static/partials/movie-detail/movie-detail.template.html',
controller: [ '$routeParams', 'Movie',
function MovieDetailController($routeParams, Movie) {
var self = this;
self.movie= Movie.get({movieId: $routeParams.movieId})
}
]
});
In the movie HTML template, I have access to the "actors" id via "$ctrl.movie.actors". But I can't figure out if there is a way to use this id to ask the server for the 'actor' object. Something like :
Actor.get({id}) to incorporate them in the movie details template.
TL;DR
What I can do now :
Actors:
<ul>
<ling-repeat="actor in $ctrl.movie.actors"> {{actor}} </li>
</ul>
result:
Actors
1
2
And I want something along the lines of :
Actors:
<ul>
<ling-repeat="actor in $ctrl.movie.actors"> {{actor.name}} </li>
</ul>
result:
Actors
Angelina Jolie
Brad Pitt
How can this be achieved ?
Thank you for any replies!
First of All you are using Angularjs 2 and Angularjs 2 is way different then Angularjs 1.*.
In this case its more javascript object manipulation rather Angularjs tricks
you can try below ways to achieve this
option1:
if you are able to edit your rest call in Django, change your code to return the movie and actor details in one js like this
{
"id": 1,
"name": "Mr & Mrs Smith",
"actors": [
1: {"id": 1,"name": "Angelina Jolie"},
2: {"id": 1,"name": "Angelina Jolie"},
]
}
And try to ng-repeat for you actor object under movie. or you can separate both the calls as your requirement.
option2:
You need to do a lazy loading at the time of loading. once your movie object is loaded, you need to call actor rest url to get all the actor object required and append them in the existing object if you are unable to make a single rest call.then in the template you can show actor detail as above.
I'm trying to print out each array item from a property in an object:
{
position:"Finance Office Assistant",
employer:"Washtenaw County Finance Department",
location:"Ann Arbor, MI",
start_date:"2012",
current: false,
end_date:"2012",
duties: [
"Item 1",
"Item 2",
"Item 3"
]
},
This object is in an array, with several other objects. I'm trying to create a function that loops through all of the objects and prints out the duties array items in an unordered list with the exact number of list items and array items.
Here is the function I'm trying to write to do the task
$scope.dutyList = function() {
var arrayLength = $scope.duties.length;
while (arrayLength > 0) {
console.log("dutyList run")
document.write("<li> {{ dutyList }} </li>");
--arrayLength;
}
}
You don't need a function to handle displaying data like this. Angular's ngRepeat is for this. To access the second level of of your data set you can nest two repeats in your unordered list. The first one (in a div) repeats the first layer of your data, and exposes the second layer, which repeat in the <li> tag:
<ul>
<div ng-repeat="d in data">
<li ng-repeat="duty in d.duties">{{duty}}</li>
</div>
</ul>
Plunker
As a general rule, you don't want to write directly to the document when using a framework like Angular. Instead, you should use the built in templating system and directives to render your page.
I'm making some assumptions about the end goal here, but, assuming the array of objects can be accessed by the controller and attached to the scope, you could print your unordered list of duties for each position using something like the following.
angular.module('myApp', []).controller('myCtrl', function($scope){
$scope.foo = [{
position:"Finance Office Assistant",
employer:"Washtenaw County Finance Department",
location:"Ann Arbor, MI",
start_date:"2012",
current: false,
end_date:"2012",
duties: [
"Item 1",
"Item 2",
"Item 3"
]
}, {
position:"Another Position",
employer:"Another Employer",
location:"Ann Arbor, MI",
start_date:"2012",
current: false,
end_date:"2012",
duties: [
"2nd Object, Item 1",
"2nd Object, Item 2",
"2nd Object, Item 3"
]
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='myApp' ng-controller='myCtrl'>
<div ng-repeat='bar in foo'>
<h1>{{ bar.position }}</h1>
<ul>
<li ng-repeat='duty in bar.duties'>
{{ duty }}
</li>
</ul>
</div>
</div>
I'm completely rebuilding my website (originally hacked together with Wordpress) using Laravel and AngularJS. It's been a massive learning experience and I think I'm nearly there but for one problem.
On my site 'schemes' (or courses) are made up of 'units' which are made up of 'lessons'. Retrieving this data is fine, using Eloquent I retrieve valid JSON like this made up example...
[
{
"id": "1", //Scheme Id
"title": "Sports",
"description": "This is a Sports course!",
"units": [
{
"id": "1",
"title": "Tennis",
"lessons": [
{
"id": "6",
"title": "Serving"
},
{
"id": "7",
"title": "Hitting the ball with top-spin"
}
]
},
{
"id": "2",
"title": "Athletics",
"lessons": [
{
"id": "1",
"title": "Long Jump"
},
{
"id": "2",
"title": "Hurdling Technique"
}
]
},
{
"id": "4",
"title": "Golf",
"lessons": [
{
"id": "4",
"title": "Pitching"
},
{
"id": "5",
"title": "Putting"
}
]
}
]
}
....
]
Separately I have a simple array of completed lesson ids for a particular user like this...
[2, 6, 8, 9] ///User has completed lessons with ids of 2,6,8 and 9
In my view I'm using nested ng-repeat loops like so...
...
<div ng-controller="SchemesController">
<div ng-repeat="scheme in schemes">
<h1>{{scheme.title}}</h1>
<div ng-repeat="unit in scheme.units">
<h3>{{unit.title}}</h3>
<div ng-repeat="lesson in unit.lessons">
<div>{{lesson.title}}: {{status}}</div>
</div>
</div>
</div>
</div><!--[end of ng-controller="SchemesController"]-->
....
SchemesController (v simple!) looks like this...
var app = angular.module('schemesApp', []);
app.controller('SchemesController', function($scope){
$scope.schemes=jsonData;
});
The problem is I have no idea how to populate the {{status}} field which I want to state simply 'Complete' or 'Incomplete. I investigated whether I could somehow add this info to my original array like this...
"lessons": [
{
"id": "6",
"title": "Serving",
"status": "Complete" //populated somehow
},
{
"id": "7",
"title": "Hitting the ball with top-spin",
}
]
but I got nowhere slowly. Is there a way to do this (I've played around with underscore.js and felt this could help?).
Or do I populate {{status}} from creating and calling a javascript function?!?
ANY help that anyone could offer would be incredible. I'm a school teacher and for some sadistic reason I find a bit of programming/web design a fun use of my spare time so I apologise if this is a stupid question. THANKS in advance!!!
btw if anyone has a better 'title' for this question then please let me know.
I'm assuming you don't need to persist the status back to the database...
This is where you're having the problem:
<div>{{lesson.title}}: {{status}}</div>
You really don't need to store the status in your data model, because it's just used for presentation purposes.
Let's say your array of completed lessons is defined like this:
$scope.completedLessons = [1, 2, 3, 4, 5] // Or however you'd assign it
You need to create a function in your scope like this:
$scope.isLessonCompleted = function(lessonId) {
return $scope.completedLessons.indexOf(lessonId) > -1;
};
Then you need to change the html from above to this:
<div>{{lesson.title}}: {{isLessonCompleted(lesson.id) && 'Complete' || 'Incomplete'}}</div>
If lessons are also a model and each lesson should have a status, which isn't a column/field in your table but is something you'll add logic to determine, you could add a custom model accessor by adding the following to your models/Lesson.php:
// Append custom accessor attributes
protected $appends = ['status'];
public function getStatusAttribute() {
// Add logic here
return 'Complete';
}
This way, when you use Eloquent to retrieve your data, you'll also see a status attribute as part of the object, so you could then access it as usual $lesson->status (PHP) or lesson.status (JS).
For more information, see the official Laravel documentation on accessors and mutators