I have a simple ng-repeat iterating through an array of objects.
The ng-repeat contains a ng-model input element for which I need to use a dynamic value as the array index. Probably very unclear explanation so here is the code :
<div ng-repeat="property in current_data.object_subtype.object_property_type" ng-init="set_input_state()" class="input-group ng-scope disabled">
<span class="input-group-addon">{{property.name}}</span>
<input type="text" placeholder="{{property.name}}" ng-model="current_data.properties[getIndexFromId(current_data.properties, property.object_property_type_id)].value" class="form-control" disabled="disabled">
The problem is that the input stays empty. I've tested some combinations and found this to work :
getIndexFromId(current_data.properties, property.object_property_type_id) == 0
current_data.properties[0].value gives the expected output
So somehow getIndexFromId(current_data.properties, property.object_property_type_id)is not well accepted by Angular or I made a stupid mistake somewhere ...
Does anyone know what's wrong with this?
Thanks!
[edit]
Here is a sample of the data behind all this :
{
"id": 1,
"name": "Robert Smith",
"object_subtype_id": 1,
"object_subtype": {
"id": 1,
"description": "Manager",
"object_property_type": [
{
"id": 1,
"description": "Phone number"
},
{
"id": 2,
"description": "Hair color"
},
{
"id": 3,
"description": "Nickname"
}
]
},
"properties": [
{
"id": 1,
"value": "819-583-4855",
"object_property_type_id": 1
},
{
"id": 2,
"value": "Mauves",
"object_property_type_id": 2
},
{
"id": 3,
"value": "Bob",
"object_property_type_id": 3
}
]
}
From what I've seen of Angular, the content of the attributes are not executed as javascript. It's a custom parsed and executed mini-language that doesn't support complex indexing.
With that said, its probably for the best. Any sufficiently complex logic should be handled by the controller or a service.
function MyController($scope) {
$scope.set_current_data_value = function (current_data, property) {
var index = $scope.getIndexFromId(current_data.properties, property.object_property_type_id);
current_data.properties[index].value = $scope.property_name;
}
}
Then your html would look something like:
<input type="text" placeholder="{{property.name}}" ng-model="property_name" ng-change="set_current_data_value(current_data, property)" class="form-control" disabled="disabled">
You may also be able to use ng-submit if you don't need to update your model in real time.
Related
currently I stuck with an angularjs problem. The following scenario:
I have a Game entity and a Team entity. One Game can hold multiple Team objects. (ManyToMany Relationship)
In my frontend application I want to add a new Game with optional Teams. For the Teams I decided to use two dropdown-menus (each menu for one team).
Now I am not able to give the ng-model the correct values.
I tried something like this but it might be wrong:
<select class="form-control" ng-options="team.teamname for team in teams
track by team.id" ng-model="game.teams[0]">
<option value="" selected>-- No Team --</option>
</select>
<select class="form-control" ng-options="team.teamname for team in teams
track by team.id" ng-model="game.teams[1]">
<option value="" selected>-- No Team --</option>
</select>
As soon as I click the save button i get an error message "400: Unable to process JSON":
Possibly unhandled rejection: {"data":{"code":400,"message":"Unable to process JSON"},"status":400,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","data":{"teams":{"0":{"id":1,"games":[{"id":1,"date":20180810}],"teamname":"BVB"},"1":{"id":2,"games":[{"id":1,"date":20180810}],"teamname":"FCB"}},"date":"20180810"},"url":"/api/games","headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json;charset=utf-8"}},"statusText":"Bad Request"}
When creating the two Teams for a Game with Postman it works:
{
"date": 20180810,
"teams": [{"id": 1}, {"id": 2}]
}
Output:
{
"id": 1,
"date": 20180810,
"teams": [
{
"id": 1,
"games": [
{
"id": 1,
"date": 20180810
}
],
"teamname": "BVB"
},
{
"id": 2,
"games": [
{
"id": 1,
"date": 20180810
}
],
"teamname": "FCB"
}
]
}
Any suggestions how to set the ng-model (Game) with the values of the first and second dropdown-menus? thanks
I have added a screenshot of the form that i want to have:
If i understand well, when you do the request with postman, you send this:
{
"date": 20180810,
"teams": [{"id": 1}, {"id": 2}]
}
But your angular form is actually sending this:
{
"date": "20180810"
"teams": {
"0": {
"id": 1,
"games": [
{
"id": 1,
"date": 20180810
}
],
"teamname": "BVB"
},
"1": {
"id": 2,
"games": [
{
"id": 1,
"date": 20180810
}
],
"teamname": "FCB"
}
}
}
While the date looks fine, your teams is an object but your backend is expecting an array. You also have additional informations in your teams (like games and teamname, but i can't know if this is a problem for your backend.
Most of the time this kind of problems with Angularjs are not in the html template but in the controller. In your controller you should have something like this:
scope.game = {
date: 'something',
teams: []
};
I think your problem is that you don't initialize scope.game.teams as an array properly. So ng-model just initliaze it by itself with an object.
From what i gather you want to add multiple teams for each game, follow the checklist model, its probably what you want, https://vitalets.github.io/checklist-model/ from there you can pass the server a list of games for each team
Not sure if the question makes sense so better to provide a code example.
{
"data": {
"whatever": [{
"id": "abcd12312",
"title": null,
"value": null,
"options": [
{
"text": "My text {{value}} one",
"value": "email#address.com"
},
{
"text": "My text [value] one",
"value": "email#address.com"
}
]
}]
}
}
So I was thinking can you do anything with Mustache or is there another way without having to write JavaScript to insert the value inside the text?
What I am trying to do is to allow the user to change the text to what ever they want but have a pointer to the value which will be dynamic based on what email address the entered on a previous page.
I'll keep this short.
http://codepen.io/anon/pen/waXWpw?editors=101
Here's something I made that hopefully illustrates my problem (I also hope I have Plunker working correctly...). The first dropdown is my attempt, and the other is one I took from another working Plunker that no longer works here...
I simply can't figure out the reason why this isn't working. Essentially I want the user to be able to select a number of rounds from a dropdown, but no matter what I try I can't get ngOptions to function. I simply get "undefined" inside the dropdown, and no other options appear.
EDIT: I fixed the Plunker, and suddenly ngOptions started working, so now my problem is that I have no idea how to replicate my problem. I'll have to include my actual code here to see if anyone can spot the error.
To be clear, everything else on the page is functioning well, including ngMessages, ngAnimate, Angular UI, and other form elements, so I'll include only the relevant HTML.
HTML:
<div ng-controller="CreateController as create">
<form name="creationForm" novalidate>
<div>
<select name="numberOfRounds"
ng-model="create.numberOfRounds"
ng-options="item.rounds as item.name for item in create.possibleNumbersOfRounds"
required>
</select>
<label>Number of Rounds</label>
</div>
</form>
</div>
JS (Controller):
angular
.module('TabIt')
.controller('CreateController', ['$state', '$scope', 'TournamentFactory', function ($state, $scope, TournamentFactory) {
this.possibleNumbersOfRounds = [
{ "rounds": 0, "name": "Please make a selection"},
{ "rounds": 2, "name": "2 rounds" },
{ "rounds": 3, "name": "3 rounds" },
{ "rounds": 4, "name": "4 rounds" },
{ "rounds": 5, "name": "5 rounds" },
{ "rounds": 6, "name": "6 rounds" },
{ "rounds": 7, "name": "7 rounds" },
{ "rounds": 8, "name": "8 rounds" },
{ "rounds": 9, "name": "9 rounds" }
];
this.numberOfRounds = this.possibleNumbersOfRounds[0].code;
}]);
I have a little problem.. I've got this JSON data:
[
{
"students": {
"student_id": "2",
"student_school": "1",
"student_name": "Charles"
},
"parents": [
{
"parent_id": "2",
"parent_school": "1",
"parent_name": "Tim"
}
]
},
{
"students": {
"student_id": "3",
"student_school": "1",
"student_name": "Johnny"
},
"parents": [
{
"parent_id": "3",
"parent_school": "1",
"parent_name": "Kate"
}
]
}
]
The problem is that I try to call to my html page by angular:
{{student.student.student_name}}
Yeah it works but when I want to call the parents data it doesn´t...
{{student.parents.parent_name}}
Simply:
<div ng-repeat="student in data">
{{student.students.student_name}}
{{student.parents[0].parent_name}}
</div>
Or define function in scope called for example getParentDescription and than
<div ng-repeat="student in data">
{{student.students.student_name}}
{{getParentDescription(student)}}
</div>
Because parents is an array. You must specify the index (0 in your case). See the response here : How to get value from a nested JSON array in AngularJS template?
You can't access child scopes directly from parents. See the comment by Vittorio suggesting<ng-repeat="child in parent.children"/> also Binding to Primitives
I'm guessing student is from an ng-repeat where you go through each object in the array.
Take a closer look at your JSON. While "students": {} points to an object, "parents": [] points to an array. Fix your JSON and it'll be fine
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