First, here is all the code that leads me to the error I'm getting:
The JSON:
[
{
"Id": 0,
"UserName": "uniqueusername",
"Photo": "base64string",
"Email": "user#user.com",
"Office": "Location "
},
{
"Id": 1,
"UserName": "uniqueusername",
"Photo": "base64string",
"Email": "user#user.com",
"Office": "Location"
},
{
"Id": 2,
"UserName": "uniqueusername",
"Photo": "base64string",
"Email": "user#user.com",
"Office": "Location"
},
{
"Id": 3,
"UserName": "uniqueusername",
"Photo": "base64string",
"Email": "user#user.com",
"Office": "Location"
},
{
"Id": 4,
"UserName": "uniqueusername",
"Photo": "base64string",
"Email": "user#user.com",
"Office": "Location"
}
]
It is generated using this function in my controller:
List<string> Names = arepo.GetAllAvionteUsers();
List<UserPreviewViewModel> AllUsers = new List<UserPreviewViewModel>();
int count = 0;
foreach(string name in Names)
{
UserPreviewViewModel preview = new UserPreviewViewModel(name);
preview.Id = count;
AllUsers.Add(preview);
count++;
if (count == 10) break;
}
return Json(new { Users = JsonConvert.SerializeObject(AllUsers, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore}) }, JsonRequestBehavior.AllowGet);
The View Model:
public int Id { get; set; }
public string UserName { get; set; }
public string Photo { get; set; }
public string Email { get; set; }
public string Office { get; set; }
the angular controller:
angular.module('app.module')
.factory('Users', ['$http', function UsersFactory($http) {
return {
AllUsers: function () {
return $http({ method: 'GET', url: '/Controller/GetAllUsers' });
}
}
}]);
angular.module('app.module')
.controller('UserController', ['$scope', 'Users', function ($scope, Users) {
var vm = this;
Users.AllUsers().success(function (data) {
vm.users = JSON.stringify(data.Users);
});
}]);
And finally the view:
<table class="dataTable row-border hover" datatable="ng" dt-instance="vm.dtInstance"
dt-options="vm.dtOptions">
<thead>
<tr>
<th class="secondary-text">
<div class="table-header">
<span class="column-title">Id</span>
</div>
</th>
<th class="secondary-text">
<div class="table-header">
<span class="column-title">Name</span>
</div>
</th>
<th class="secondary-text">
<div class="table-header">
<span class="column-title">Photo</span>
</div>
</th>
<th class="secondary-text">
<div class="table-header">
<span class="column-title">Email</span>
</div>
</th>
<th class="secondary-text">
<div class="table-header">
<span class="column-title">Office</span>
</div>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in vm.users">
<td>{{user.Id}}</td>
<td>{{user.UserName}}</td>
<td><img class="product-image" ng-src="data:img/jpg;base64,{{user.Photo}}"></td>
<td>{{user.EmailAddress}}</td>
<td>{{user.Office}}</td>
</tr>
</tbody>
</table>
Every time that I try to run this code I get the following error from my JSON:
angular.js:13920 Error: [ngRepeat:dupes] Duplicates in a repeater are
not allowed. Use 'track by' expression to specify unique keys.
Repeater: user in vm.users, Duplicate key: string:\, Duplicate value:
\
I have tried to use angular's suggested fix, which is track by $index and all that does is cause my page to freeze.
I have tried to take out the Formatting.Indented when I return the JSON string and all that does is give me the same error as well as taking out the ReferenceLoopHandling part and also getting the same error.
In the angular controller I tried to do JSON.parse(data) and I get the following error:
angular.js:13920 SyntaxError: Unexpected token o in JSON at position 1
When I try to do let users = data.Users and then do let count = users.length it gives me the number 85941 which seems like it is counting every single character in the string.
When I do a console.log(data) it gives me the JSON that I pasted above (I did change usernames, emails, and locations to keep my user's info safe).
At this point I have absolutely no clue what is wrong here or how to fix it, any help would be greatly appreciated.
Thanks!
Although I am not entirely sure as to why this error occurred in first place, the fix for it was not to return JSON from the controller. I modified my return statement like so:
return Json(JsonConvert.SerializeObject(AllUsers, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore}), JsonRequestBehavior.AllowGet);
Then in the angular controller i did:
vm.users = JSON.parse(data);
That gave me the proper JSON array and now it works perfectly.
Related
I'm trying to setup hotkeys for an old project that still uses angular 1.x and one of the features I was trying to add would be to select the first row from a table that is created with an NG-REPEAT. I've been able to add in other functionality such has moving the selected row up / down because I pass in the selected row on ng-click="setSelected(this)" which then lets me save the row and move it with selectedRow.$$prevSibiling or selectedRow.$$nextSibiling.
What I'm having a hard time figuring out is how can I set the selectedRow from the controller.
Here is a quick example:
http://plnkr.co/edit/6jPHlYwkgF5raRWt?open=lib%2Fscript.js
JS:
App.controller('ActivitiesCtrl', [function() {
var vm = this;
vm.selectedRow = "Not set";
vm.activities = [
{
"id": 1,
"code": "ABC",
"person": "Joe"
},
{
"id": 2,
"code": "DFF",
"person": "Sally"
},
{
"id": 3,
"code": "ABC",
"person": "Sue"
},
{
"id": 4,
"code": "124",
"person": "Sam"
},
];
vm.setSelected = function(row) {
vm.selectedRow.selected = false;
vm.selectedRow = row;
vm.selectedRow.selected = true;
}
vm.moveNext = function() {
vm.setSelected(vm.selectedRow.$$nextSibling)
}
vm.setFirst = function() {
vm.setSelected("How do I set it...");
// How to set it? vm.setSelected(?????)
}
}]);
HTML:
<div ng-controller="ActivitiesCtrl as vm">
<table>
<thead>
<th>Id</th>
<th>Code</th>
<th>Person</th>
</thead>
<tbody>
<tr ng-repeat="activity in vm.activities track by activity.id" ng-click="vm.setSelected(this)" ng-class="{info: selected}">
<td>{{activity.id}}</td>
<td>{{activity.code}}</td>
<td>{{activity.person}}</td>
</tr>
</tbody>
</table>
{{vm.selectedRow | json}}
<hr />
<button ng-click="vm.setFirst()">Set First</button>
<button ng-click="vm.moveNext()">Next</button>
</div>
You can do this by setting the actual object from the array as selectedRow rather than using this and set the class by checking if selectedRow === activity in the ng-class.
This approach doesn't require mutating the objects
<tr
ng-repeat="activity in vm.activities track by activity.id"
ng-click="vm.setSelected(activity)"
ng-class="{info: vm.selectedRow == activity}"
>
Then you can use Array#findIndex() to get the current selectedRow index in the array and if a next one exists use it or go back to the first.
For the setFirst() you just use vm.activities[0]
vm.selectedRow = null;
vm.setSelected = function (row) {
vm.selectedRow = row;
};
vm.moveNext = function () {
const {selectedRow:curr, activities:act} = vm;
if (curr !== null) {
let idx = act.findIndex(e => e == curr) + 1;
let next = act[idx] || act[0];
vm.setSelected(next);
}
};
vm.setFirst = function () {
vm.setSelected(vm.activities[0]);
};
Working plunker
Here is the link with test working example.
enter code here
http://plnkr.co/edit/7mTvRB0ZlHOQwOIc?preview
I have 2 api's called teachers and sessions.
teachers JSON file:
[
{
"teacherName": "Binky Alderwick",
"id": "01"
},
{
"teacherName": "Basilio Gregg",
"id": "02"
},
{
"teacherName": "Binky Alderwick",
"id": "03"
},
{
"teacherName": "Cole Moxom",
"id": "04"
}
]
sessions JSON file:
[
{
"id":"001",
"sessionName": "Chemistry",
"notes": "Chemistry is the study of matter, its properties",
"teacherIds": ["01","03"]<==========
},
{
"id":"002",
"sessionName": "Physics",
"notes": "Physics is the natural science that studies matter and its motion ",
"teacherIds": ["02","04"]
},
{
"id":"003",
"sessionName": "Maths",
"notes": "Mathematics includes the study of such topics as quantity",
"teacherIds": ["01","04"]<=========
},
{
"id":"004",
"sessionName": "Biology",
"notes": "Biology is the natural science that studies life and living organisms",
"teacherIds": ["02","04"]
}
]
Now i am displaying all the teachers in the template like this:
In the sessions JSON, I have mentioned the teacherIDs which is of array, I want to display the sessions of the particular teacher based upon the teachersID.
For ex the sessions (Chemistry & Maths) contains teacherID as (01),So i want to display these 2 sessions(Chemistry & Maths) under Teacher 1(i,e Binky Alderwick) Like this:
I should get all the properties of the session object based on the teacherId.
Stackblitz DEMO
This works in your stackblitz
<h4>Teachers</h4>
<div class="cust-detail" *ngFor="let teacher of teachers">
<tr>
<td>Name</td>
<td>{{ teacher.teacherName }}</td>
</tr>
<tr>
<td>Sessions</td>
<div *ngFor="let session of sessions">
<span *ngFor="let id of session.teacherId">
<span *ngIf="id == teacher.id">
<h2>{{ session.sessionName }}, {{ session.id }}</h2>
<p>{{session.notes}}</p>
</span>
</span>
</div>
</tr>
<hr>
</div>
Dont forget to remove the arrows from your JSON before putting this in.
You need to manipulate your JSON for the same like below -
getManipulatedData() {
this.teachers && this.teachers.forEach(res => {
res['subjects'] = [];
this.sessions.forEach(obj => {
if (obj['teacherId'].includes(res.id)){
res['subjects'].push({subject: obj.sessionName, notes: obj.notes})
}
});
});
}
<h4>Teachers</h4>
<div class="cust-detail" *ngFor="let teacher of teachers">
<tr>
<td>Name</td>
<td>{{teacher.teacherName }}</td>
</tr>
<tr>
<td>Sessions</td>
<td><br>
<div *ngFor='let subject of teacher?.subjects'>
<h2>{{subject?.subject}}</h2>
<p>{{subject?.notes}}</p>
</div>
</td>
</tr>
<hr>
</div>
Working Example
Update -
Also you need to call this method on API call end like this -
ngOnInit() {
this.myService.getContacts()
.subscribe(res => {
this.teachers = res;
this.getManipulatedData();
});
this.myService.getWorkers()
.subscribe(res => {
this.sessions = res;
this.getManipulatedData();
});
}
I am aware that it may be Duplicate Question, but I tried that too but it didnt work it. So, I am posting my Question now. My Question is Apply the Date range filter using Angular js only one column.
Here is MY code:
HTML:
<div ng-app="myApp" ng-controller="myCtrl">
<div>
<table>
<tr>
<td>Start Date</td>
<td><input type="text" name="S_Date" ng-model="startDate"/></td>
<td>End Date</td>
<td><input type="text" name="E_Date" ng-model="endDate"/>
</tr>
</table>
</div>
<table>
<tr>
<th>Date</th>.
<th>Stock</th>
</tr>
<tr ng-repeat="subject in records |myfilter:startDate:endDate">
<td>{{ subject.name * 1000|date:'dd-MM-yyyy'}}<td>
<td>{{ subject.marks }}</td>
</tr>
</table>
Angular JS:
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.records = [
{
"name" : "2016-08-01",
"marks" : 250
},{
"name" : "2016-08-02",
"marks" : 150
},{
"name" : "2016-08-03",
"marks" : 100
},{
"name" : "2016-08-04",
"marks" : 150
},{
"name" : "2016-05-01",
"marks" : 750
},{
"name" : "2016-05-02",
"marks" : 1500
},{
"name" : "2016-03-03",
"marks" : 500
},{
"name" : "2016-04-04",
"marks" : 650
}
]
function parseDate(input) {
var parts = input.split('-');
return new Date(parts[2], parts[1]-1, parts[0]);
}
app.filter("myfilter", function() {
return function(items, from1, to) {
var df = parseDate(from1);
var dt = parseDate(to);
alert(df)
alert(dt)
var result = [];
for (var i=0; i<items.length; i++){
var tf = new Date(items[i].startDate * 1000),
tt = new Date(items[i].endDate * 1000);
if (tf > df && tt < dt) {
result.push(items[i]);
}
}
return result;
};
});
});
</script>
Please advice me Where I am going wrong.Please suggest me.Thanks in advance.
I recommend you to use moment.js library: http://momentjs.com/
Here is working plunkr with your range filter: https://plnkr.co/edit/dfpsBI0uom5ZAEnDF3wM?p=info
<div ng-controller="MainCtrl">
<table>
<tr>
<td>Start Date</td>
<td>
<input type="text" name="S_Date" ng-model="startDate" />
</td>
<td>End Date</td>
<td>
<input type="text" name="E_Date" ng-model="endDate" />
</td>
</tr>
</table>
<table>
<tr>
<th>Date</th>.
<th>Stock</th>
</tr>
<tr ng-repeat="subject in records | myfilter: startDate: endDate">
<td>{{ subject.name | date:'dd-MM-yyyy'}}</td>
<td>{{ subject.marks }}</td>
</tr>
</table>
</div>
app.controller('MainCtrl', function($scope) {
$scope.startDate = "2016-08-01";
$scope.endDate = "2016-08-03";
$scope.records = [{
"name": "2016-08-01",
"marks": 250
}, {
"name": "2016-08-02",
"marks": 150
}, {
"name": "2016-08-03",
"marks": 100
}, {
"name": "2016-08-04",
"marks": 150
}, {
"name": "2016-05-01",
"marks": 750
}, {
"name": "2016-05-02",
"marks": 1500
}, {
"name": "2016-03-03",
"marks": 500
}, {
"name": "2016-04-04",
"marks": 650
}];
});
app.filter("myfilter", function($filter) {
return function(items, from, to) {
return $filter('filter')(items, "name", function(v) {
var date = moment(v);
return date >= moment(from) && date <= moment(to);
});
};
});
$scope.Customfilterobj`enter code here` = { status: "Complete",StartDate: "2017-02-01T08:00:00",EndDate: "2018-02-01T08:00:00 " };
<tr ng-repeat="dt in data | filter: {Status: Customfilterobj.status} | dateRange:Customfilterobj.StartDate:Customfilterobj.EndDate">
Here we have use two filters as below:
filter: {Status: Customfilterobj.status} work as compare "complete" value with Status of data collection.
dateRange:Customfilterobj.StartScheuleDate:Customfilterobj.EndScheuleDate" : dateRange is custom filter for compare Expiration_date between StartDate and EndDate.
app.filter('dateRange', function () {
return function (data, greaterThan, lowerThan) {
if (greaterThan != null && lowerThan != null && greaterThan != undefined && lowerThan != undefined) {
data = data.filter(function (item) {
if (item.Expiration_date != null) {
var exDate = new Date(item.Expiration_date);
return exDate >= new Date(greaterThan) && exDate <= new Date(lowerThan);
}
});
}
return data;
};
});
Adding off of Roman Koliada's plunker. His process has a small issue in the usage of the angular $filter. I have the updated here:
https://plnkr.co/edit/l4t4Fln4HhmZupbmOFki?p=preview
New filter:
app.filter("myfilter", function($filter) {
return function(items, from, to, dateField) {
startDate = moment(from);
endDate = moment(to);
return $filter('filter')(items, function(elem) {
var date = moment(elem[dateField]);
return date >= startDate && date <= endDate;
});
};
});
The issue was that the function input into $filter function was the third param, and loops over every attribute of every object in the list. Console logging his plunker calls moment() on every single attribute of every object. By instead inputting a function as the second param, as the expression instead of the comparator - we can call the comparison only on the date field.
Angular doc: https://docs.angularjs.org/api/ng/filter/filter
I am having trouble passing JSON object to my view. I am using angular to later bind the data to my view. But when I execute the page, the table in blank. Please see the code below
Code in my view
<div class="container" ng-init="courses = #Html.Raw(Model)">
<div class="row">
<div class="span10">
<table class="table table-condensed table-hover">
<tr>
<th>Course</th>
<th>Course Name</th>
<th>Instructor</th>
</tr>
<tr ng-repeat="course in courses">
<td>{{course.number}}</td>
<td>{{course.name}}</td>
<td>{{course.instructor}}</td>
</tr>
</table>
</div>
</div>
</div>
Code in my controller
public class CoursesController : Controller
{
// GET: Hello
public ActionResult Index()
{
return View("Index", "", GetSerialisedCourseVm());
}
public string GetSerialisedCourseVm()
{
var courses = new[]
{
new CourseVM {Number= "100", Name= "Physis", Instructor = "Abc"},
new CourseVM {Number= "101", Name= "Chemistry", Instructor = "test"},
new CourseVM {Number= "102", Name= "Biology", Instructor = "Mac"},
new CourseVM {Number= "103", Name= "History", Instructor = "Jack"},
new CourseVM {Number= "104", Name= "Maths", Instructor = "Ren"}
};
var settings = new JsonSerializerSettings{ContractResolver = new CamelCasePropertyNamesContractResolver()};
return JsonConvert.SerializeObject(courses, settings);
}
}
public class CourseVM
{
public string Number { get; set; }
public string Name { get; set; }
public string Instructor { get; set; }
}
when i do an F12 i can see the following error
angular.min.js:62 Error: Unexpected end of expression: courses = [{
at Error (native)
at g (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:67:426)
at J (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:71:164)
at A (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:70:288)
at m (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:70:204)
at x (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:70:70)
at t (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:69:454)
at s (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:69:384)
at p (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:69:321)
at o (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:69:251) <div class="container" ng-init="courses = [{" number":"100","name":"physis","instructor":"Abc"},{"number":"101","name":"chemistry","instructor":"test"},{"number":"102","name":"biology","instructor":"Mac"},{"number":"103","name":"history","instructor":"Jack"},{"number":"104","name":"maths","instructor":"Ren"}]"="">
Using the unminified version of angular
angular.js:13294 Error: [$parse:ueoe] Unexpected end of expression: courses = [{
http://errors.angularjs.org/1.5.2/$parse/ueoe?p0=courses%20%3D%20%5B%7B
at http://localhost:81/Scripts/angular.js:68:12
at Object.AST.peekToken (http://localhost:81/Scripts/angular.js:13895:13)
at Object.AST.object (http://localhost:81/Scripts/angular.js:13851:14)
at Object.AST.primary (http://localhost:81/Scripts/angular.js:13769:22)
at Object.AST.unary (http://localhost:81/Scripts/angular.js:13757:19)
at Object.AST.multiplicative (http://localhost:81/Scripts/angular.js:13744:21)
at Object.AST.additive (http://localhost:81/Scripts/angular.js:13735:21)
at Object.AST.relational (http://localhost:81/Scripts/angular.js:13726:21)
at Object.AST.equality (http://localhost:81/Scripts/angular.js:13717:21)
at Object.AST.logicalAND (http://localhost:81/Scripts/angular.js:13709:21) <div class="container" ng-init="courses = [{" number":"100","name":"physis","instructor":"Abc"},{"number":"101","name":"chemistry","instructor":"test"},{"number":"102","name":"biology","instructor":"Mac"},{"number":"103","name":"history","instructor":"Jack"},{"number":"104","name":"maths","instructor":"Ren"}]"="">
Output of #Html.Raw(Model) in the view
[{"number":"100","name":"Physis","instructor":"Abc"},{"number":"101","name":"Chemistry","instructor":"test"},{"number":"102","name":"Biology","instructor":"Mac"},{"number":"103","name":"History","instructor":"Jack"},{"number":"104","name":"Maths","instructor":"Ren"}]
The solution is simply to replace all the " marks with ' marks.
In your output for model, you have this:
[{"number":"100","name":"Physis","instructor":"Abc"},{"number":"101","name":"Chemistry","instructor":"test"},{"number":"102","name":"Biology","instructor":"Mac"},{"number":"103","name":"History","instructor":"Jack"},{"number":"104","name":"Maths","instructor":"Ren"}]
The " marks there are ending the ng-init attribute, causing it to only see ng-init="courses = [{".
Data Flow
Factory
set up a factory to get your data (where data is your JSON array)
.factory('homeFactory', [ function(){
return{
getData: function(){
return data
}
};
}]);
Controller
then in your controller you must use your factory
.controller('homeCtrl', [ '$scope','homeFactory', function($scope, homeFactory){
$scope.data = {};
homeFactory.getData().then(function(res){
$scope.data= res.data;
});
}]);
View
then in your view
just throw the curly bracket notation in a for each (this assumes that name is a json key in your array) or you can just print out data
<div ng-repeat="value in data">
{{value.name}}
</div>
please ask if there is something unclear and I will update this answer.
I have factory, that send request to get some data. After responce, i will receive it in controller and create scope list. Than i must to filter this list by checking checkboxes. I'v receive results, but they not visible. Help me pls...
$scope.checkRooms = [];
$scope.filterRooms = function(app) {
return function(p) {
for (var i in $scope.checkRooms) {
if (p.rooms == $scope.uniqueRooms[i] && $scope.checkRooms[i]) {
return true;
}
}
};
};
UPDATE 2
Here is working fiddle . Now how to sort by ASC rooms numbers? "orderBy" function sort correct but rooms indexes sort wrong
Ok here's a slightly different approach whereby the filtering is done in the controller rather than using the filter:expression in your ng-repeat.
Not the only way to do it but I think you should definitely think about removing any watch functions from your controllers they make it really difficult to test your controllers.
Fiddle
HTML
<div class="filter-wrap" ng-controller="mainController">
<div class="main-filter">
<div class="form-group">
<span class="gr-head">
Rooms count
</span>
<div class="check-control" ng-repeat="room in uniqueRooms | orderBy: room">
<input
type="checkbox"
name="room_cnt"
ng-model="checkboxes[room]"
ng-change='onChecked(filterRoom)'
/>
<label>{{room}}</label>
</div>
</div>
</div>
<table>
<thead>
<tr>
<th>
<span>Rooms</span>
</th>
<th>
<span>Size</span>
</th>
<th>
<span>Price</span>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="app in filteredApps">
<td>{{app.rooms}}</td>
<td>{{app.size}}</td>
<td>{{app.price}}</td>
</tr>
</tbody>
</table>
<div class="result">
<h2>SCOPE size</h2>
{{filteredRooms}}
</div>
</div>
JS
var sortApp = angular.module('sortApp',[]);
sortApp.controller('mainController', function($scope, $timeout) {
$scope.apps = [
{
"rooms": 2,
"size": 55.50,
"price": 55500.00,
},
{
"rooms": 1,
"size": 25.50,
"price": 45000.00,
},
{
"rooms": 8,
"size": 28,
"price": 15500.00,
},
{
"rooms": 1,
"size": 28,
"price": 15500.00,
},
{
"rooms": 8,
"size": 28,
"price": 15500.00,
},
{
"rooms": 3,
"size": 120.55,
"price": 88990.00,
},
{
"rooms": 3,
"size": 120.55,
"price": 88990.00,
}
];
$scope.filteredApps = $scope.apps;
$scope.uniqueRooms = uniqueItems($scope.apps, 'rooms');
$scope.onChecked = filterRooms;
$scope.checkboxes = createCheckboxes($scope.uniqueRooms);
function filterRooms(checkboxes){
$scope.filteredApps = [];
angular.forEach($scope.apps, function(app){
if($scope.checkboxes[app.rooms]){
$scope.filteredApps.push(app);
}
});
}
function createCheckboxes(labels){
var checkboxes = {};
angular.forEach(labels, function(label){
checkboxes[label] = true;
});
return checkboxes;
}
function uniqueItems(data, key) {
var result = [];
for (var i = 0; i < data.length; i++) {
var value = data[i][key];
if (result.indexOf(value) == -1) {
result.push(value);
}
}
return result;
};
});