I am new to angularJS and I am having trouble with binding properties of scope so two way binding can work properly. I am using sample code to generate tabs.
<div ng-app="SampleApp">
<div id="tabs" ng-controller="GridController as gridcon">
<ul>
<li ng-repeat="tab in tabs"
ng-class="{active:isActiveTab(tab.url)}"
ng-click="onClickTab(tab)">{{tab.title}}</li>
</ul>
<div id="mainView">
<div ng-include="currentTab"></div>
</div>
<input type="button" ng-click="changedata()" value="Check" />
</div>
</div>
Now my scope have two observable arrays and I want to show count of those arrays in tab title. I am using following code for controller.
var appRoot = angular.module('SampleApp', ["kendo.directives"]);
appRoot.controller('GridController', ['$scope', function ($scope) {
$scope.data1 = new kendo.data.ObservableArray([
{
issueId: 1,
issue: "County Incorrect"
},
{
issueId: 2,
issue: "City Incorrect"
},
{
issueId: 3,
issue: "Name Incorrect"
}
]);
$scope.data2 = new kendo.data.ObservableArray([
{
"id": 11,
"first_name": "James",
"last_name": "Butt",
"company_name": "Benton, John B Jr",
"address": "6649 N Blue Gum St",
"city": "New Orleans",
"county": "Bridgepoort",
"state": "LA",
"zip": 70116,
"phone1": "504-621-8927",
"phone2": "504-845-1427",
"email": "jbutt#gmail.com",
"web": "http://www.bentonjohnbjr.com"
},
{
"id": 12,
"first_name": "Josephine",
"last_name": "Darakjy",
"company_name": "Chanay, Jeffrey A Esq",
"address": "4 B Blue Ridge Blvd",
"city": "Brighton",
"county": "Livingston",
"state": "MI",
"zip": 48116,
"phone1": "810-292-9388",
"phone2": "810-374-9840",
"email": "josephine_darakjy#darakjy.org",
"web": "http://www.chanayjeffreyaesq.com"
}
]);
$scope.tabs = [{
title: 'Issue List (0)'.replace("0", $scope.data1.length),
url: 'tab1.html'
}, {
title: 'Corrected (0)'.replace("0", $scope.data2.length),
url: 'tab2.html'
}];
$scope.currentTab = 'tab1.html';
$scope.onClickTab = function (tab) {
$scope.currentTab = tab.url;
}
$scope.isActiveTab = function (tabUrl) {
return tabUrl == $scope.currentTab;
}
$scope.changedata = function () {
$scope.data1.pop();
$scope.data2.pop();
console.log($scope.data1.length);
console.log($scope.data2.length);
}
}]);
Now this works fine when you are loading page for first time. Now on a button click ("Check" button), I am modifying the arrays. What should I do so that tab title is always in sync with length of arrays ? I have tried observable objects but unless I am using binding in view, they will just notify the event. Is there no other way except handling change event of observable arrays ?
you can Copy this piece of code inside the $scope.changedata function.
$scope.tabs = [{
title: 'Issue List (0)'.replace("0", $scope.data1.length),
url: 'tab1.html'
}, {
title: 'Corrected (0)'.replace("0", $scope.data2.length),
url: 'tab2.html'
}];
Also it remains outside as well.
Related
I'm trying to filter a nested array of objects with my own objects, by idSubject. But I'm not getting the right result.
I have articles (which have subjects)
And a array of objects (which are the subjects I want to filter the articles with)
Data looks like this:
So I'm trying to filter the array of articles by its subjects.
I tried the following:
<div class="panel panel-default"
ng-repeat="searchArticle in searchArticles | filter: {subjects: filterSubjects} as articleSearchResult">
So filterSubjects is the second screenshot and SearchArticles is the first screenshot.
Without much luck.
Hope you can help, please tell me if things are still unclear.
This custom filter will help you.
Example : http://plnkr.co/edit/jMizCLxPH6DtDA5wL15Q?p=preview
HTML:
<body ng-app="myApp">
<div ng-controller="MainCtrl">
<h2>Select Subjects</h2>
<div ng-repeat="subject in subjects">
<label>
<input type="checkbox" ng-model="filterSubjects[subject.id]" ng-true-value="'{{subject.id}}'" ng-false-value="''">{{subject.name}}</label>
</div>
<h2>Filtered Articles</h2>
<div ng-repeat="searchArticle in searchArticles | subjectFilter:filterSubjects">{{searchArticle.name}}</div>
</div>
</body>
JS:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
$scope.searchArticles = [{
"name": "Article1",
"sid": "1"
}, {
"name": "Article2",
"sid": "1"
}, {
"name": "Article3",
"sid": "2"
}];
$scope.subjects = [{
"name": "Subject1",
"id": "1"
}, {
"name": "Subject2",
"id": "2"
}];
$scope.filterSubjects = [];
});
app.filter('subjectFilter', function() {
return function(articles, filterSubjects) {
filtered = articles.filter(function(e){return filterSubjects.indexOf(e.sid) >= 0},filterSubjects);
return filtered;
}
});
if you want to filter based on object :
var app = angular.module('myApp', []);
app.controller('MainCtrl', function($scope) {
$scope.searchArticles = [{
"name": "Article1",
"sid": "1"
}, {
"name": "Article2",
"sid": "1"
}, {
"name": "Article3",
"sid": "2"
}];
$scope.subjects = [{
"name": "Subject1",
"id": "1"
}, {
"name": "Subject2",
"id": "2"
}];
$scope.filterSubjects = [{
"name": "Subject1",
"id": "1"
}, {
"name": "Subject1",
"id": "2"
}];
});
app.filter('subjectFilter', function() {
return function(articles, filterSubjects) {
var sFiltered = [];
for (var i = 0; i < filterSubjects.length; i++) {
sFiltered.push(filterSubjects[i].id);
}
var filtered = articles.filter(function(e) {
return sFiltered.indexOf(e.sid) >= 0;
}, sFiltered);
return filtered;
}
});
Here in {{msg}} I can display all jason data with Selected:true or false..
but What I need is I don't want to display all the datas, when I click Save button I want to display questions.id,option.id and selected:true or false below the textbox
we will get all the json data from $scope.questions.
Home.html
<div ng-repeat="question in filteredQuestions">
<div class="label label-warning">Question {{currentPage}} of {{totalItems}}.</div>
<div class="row">
<div class="row">
<h3>{{currentPage}}. <span ng-bind-html="question.Name"></span></h3>
</div>
</div>
<div class="row text-left options">
<div class="col-md-6" ng-repeat="option in question.Options" style="float:right;">
<div class="option">
<label class="" for="{{option.Id}}">
<h4> <input id="{{option.Id}}" type="checkbox" ng-model="option.Selected" ng-change="onSelect(question, option);" />
{{option.Name}}</h4>
</label>
</div>
</div>
</div>
<div class="center"><button ng-click="save()">Save</button></div>
<div class="center"><textarea rows="5" cols="50">{{msg}}</textarea></div>
</div>
controllers.js
var HomeController = function ($scope, $http, helper) {
/*$scope.names = response.data;
$scope.detectChange=function(){
$scope.msg = 'Data sent: '+ JSON.stringify($scope.filteredQuestions);
}*/
$scope.save = function() {
$scope.msg = 'Data sent: '+ JSON.stringify($scope.questions);
}
$scope.quizName = 'data/csharp.js';
$scope.loadQuiz = function (file) {
$http.get(file)
.then(function (res) {
$scope.quiz = res.data.quiz;
$scope.config = helper.extend({}, $scope.defaultConfig, res.data.config);
$scope.questions = $scope.config.shuffleQuestions ? helper.shuffle(res.data.questions) : res.data.questions;
$scope.totalItems = $scope.questions.length;
$scope.itemsPerPage = $scope.config.pageSize;
$scope.currentPage = 1;
$scope.mode = 'quiz';
$scope.$watch('currentPage + itemsPerPage', function () {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
end = begin + $scope.itemsPerPage;
$scope.filteredQuestions = $scope.questions.slice(begin, end);
});
});
}
$scope.loadQuiz($scope.quizName);
}
HomeController.$inject = ['$scope', '$http', 'helperService'];
csharp.js
{
"quiz": {
"Id": 2,
"name": "C# and .Net Framework",
"description": "C# and .Net Quiz (contains C#, .Net Framework, Linq, etc.)",
"paragraph": "In 2015 Microsoft released ASP.NET 5.ASP.NET 5 is a significant redesign of ASP.NET.ASP.NET, MVC, and Web Pages are now merged into a single framework named MVC 6.It includes the following features:Linux support OSX support Node.js supportA ngularJS supportTag ,HelpersView, ComponentsWeb ,APIGruntJS ,supportBower, supportNo ,Visual BasicNo Web Forms"
},
"config": {
"shuffleQuestions": true,
"showPager": false,
"allowBack": true,
"autoMove": false
},
"questions": [{
"Id": 1010,
"Name": "Which of the following assemblies can be stored in Global Assembly Cache?",
"QuestionTypeId": 1,
"Options": [{
"Id": 1055,
"QuestionId": 1010,
"Name": "Private Assemblies"
}, {
"Id": 1056,
"QuestionId": 1010,
"Name": "Friend Assemblies"
}, {
"Id": 1057,
"QuestionId": 1010,
"Name": "Public Assemblies"
}, {
"Id": 1058,
"QuestionId": 1010,
"Name": "Shared Assemblies"
}]
}, {
"Id": 1019,
"Name": "Which of the following does NOT represent Integer?",
"QuestionTypeId": 1,
"Options": [{
"Id": 1055,
"QuestionId": 1010,
"Name": "Char"
}, {
"Id": 1056,
"QuestionId": 1010,
"Name": "Byte"
}, {
"Id": 1057,
"QuestionId": 1010,
"Name": "Short"
}, {
"Id": 1058,
"QuestionId": 1010,
"Name": "Long"
}]
}]
}
This is my answer of above code..here Displaying all the data
Data sent: [{"Id":1013,"Name":"Which of the following is NOT an Arithmetic operator in C#.NET?","QuestionTypeId":1,"Options":[{"Id":1055,"QuestionId":1010,"Name":"** (Double Star)","$$hashKey":"00X","Selected":false},{"Id":1057,"QuestionId":1010,"Name":"+ (Plus)","$$hashKey":"00Y","Selected":false},
"$$hashKey":"00C"}]
but I want to display the all the question id's and corresponding option id's and if it is selected,selected:true otherwise false in the format of above output
If you want to change what is presented to the user after saving you should change this function:
$scope.save = function() {
$scope.msg = 'Data sent: '+ JSON.stringify($scope.questions);
}
to something like:
$scope.save = function() {
$scope.msg = 'Question IDs:';
$scope.questions.forEach(function(el){
$scope.msg += el.Id + ',';
}
}
This for example will join all the ids of the array that conains all the questions.
To add options and selections you have to ng-model the value to some variable that you will use inside your controller.
I think you should check a little guide to angularjs two-way data binding
I can't get my search field to filter my data from my .json file below.
As soon as i start typing in the search fields, all of the items disappear.
Here is my json file that works as my database.
[{
"id": 1,
"userId": 1,
"firstName": ["Jack", "text"],
"lastName": ["Rackum", "text"],
"phone": ["33221122", "tel"]
}, {
"id": 2,
"userId": 1,
"firstName": ["Ellery", "text"],
"lastName": ["Queen", "text"]
}, {
"id": 3,
"userId": 1,
"firstName": ["Minnie", "text"],
"lastName": ["Mouse", "text"]
}]
And here is my views file for the front-end
<div class="input">
<input type="text" placeholder="Søg" ng-model="query.$">
<i class="icon"></i>
</div>
<div class="item" ng-repeat="child in children | filter:query">
<img class="image" src="images/children/1.jpg">
<div class="content" >
<div class="header">
<a>
{{ child.firstName[0] }} {{ child.lastName[0] }}
</a>
</div>
</div>
</div>
And my controllers.js file
angular.module('ContactsApp')
.controller('ListController', function ($scope, Contact) {
$scope.children = Contact.query();
$scope.fields = ['firstName', 'lastName'];
$scope.firstname = ['firstName'];
$scope.lastname = ['lastName'];
$scope.phone = ['phone'];
});
And finally my factories file
angular.module('ContactsApp')
.factory('Contact', function ($resource) {
return $resource('/api/child/:id', { id: '#id' }, {
'update': { method: 'PUT' }
});
});
It looks like filters don't work well with searching within arrays. You might need to change your data structure.
Here's a Plunker:
http://plnkr.co/edit/pC0W6YwhTB9l0CUaZWy0?p=preview
Instead of using
{{child.firstName[0]}}
I used
{{child.firstName}}
with the appropriate changes in the data.
I have the following JSON object :
[{
"Question": "Sample question One",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No"
}]
}, {
"Question": "Sample question Two",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No"
}]
}, {
"Question": "Sample question Three",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No",
}, {
"OptionId": 3,
"Option": "May be",
}]
}]
I am using a select with ng-options to iterate each question. Inside the select I am adding a dropdown with the options binded to it.
This is works properly.
Now I have to hide a div if the option selected for the second question is no and if the option selected is yes, i have to show the div.
I tried using ng-show and ng-hide based on a model property "isDetailsVisible". I thought it would be easy to bind this to the second question's answer but I am unable to think of a way to do this.
Does anyone have ideas?
This may help you I think,
In this I have seperated the display as follows
Custom directive questioninfo: for displaying the information about the selected question. This also shows the options of the selected question, but before iterating, i use filter on the options to get only available options(with value 'Yes')
Filter optionFilter: For filtering the options, I have applied the filter to select options with given value('Yes') in 'Option'
var app = angular.module('plunker', []);
app.factory('dataService', function() {
return {
data: {
"Questions": [{
"Question": "Sample question One",
"Options": [{
"OptionId": 1,
"Option": "Yes"
}, {
"OptionId": 2,
"Option": "No"
}]
}, {
"Question": "Sample question Two",
"Options": [{
"OptionId": 1,
"Option": "No"
}, {
"OptionId": 2,
"Option": "No"
}]
}]
}
};
});
// I am using this filter because options should not be many
app.filter('optionFilter', function() {
return function(items, value) {
if (!angular.isUndefined(items)) {
var arrayToReturn = [];
for (var i = 0; i < items.length; i++) {
if (items[i].Option === value) {
arrayToReturn.push(items[i]);
}
}
return arrayToReturn;
}
};
});
app.directive('questioninfo', function() {
return {
restrict: 'AE',
scope: {
selectedQuestion:'=question'
},
controller: function($scope) {},
template: '<h2>{{selectedQuestion.Question}}</h2>\
<h3>Available Options</h3>\
<div ng-repeat="option in selectedQuestion.Options|optionFilter:\'Yes\'"> \
<div ng-if="shouldShowOption(option)"><b>Option {{option.OptionId}}</b> {{option.Option}}</div>\
</div>\
\
'
};
})
app.controller('MainCtrl', function($scope, dataService) {
$scope.name = 'World';
$scope.data = dataService.data;
$scope.Questions = dataService.data.Questions;
$scope.selectedQuestion = dataService.data.Questions[1].Question;
});
HTML Code:
<body ng-controller="MainCtrl">
<h1>Select Question</h1>
<select id="s1" ng-model="selectedQuestion" ng-options="item as item.Question for item in Questions">
</select>
<h3>The selected item just for reference:</h3>
<pre>{{selectedQuestion | json}}</pre>
<hr>
<questioninfo question="selectedQuestion"></questioninfo>
</body>
</html>
Check this link [Plunker]: http://plnkr.co/edit/LIVVofC8nyYtbYYVBBCb?p=preview
Thanks Ganesh for the detailed answer. I am expecting a little more simpler way.
I think I found an answer. I updated the JSON to make it easier, but this does not impact much.
[{
"Question": "Sample question One",
"Options": ["Yes", "No"],
"SelectedOption": "Yes"
}, {
"Question": "Sample question Two",
"Options": ["Yes", "No"],
"SelectedOption": "Yes"
}, {
"Question": "Sample question Three",
"Options": ["Yes", "No"],
"SelectedOption": "Yes"
}]
on the html, I have the following :
<div class="col-md-12 nopadding" data-ng-repeat="Question in Questions">
<select ng-model="question.SelectedOption" ng-options="option for option in Question.Options"> </select></div>
and for the div which I have to show and hide, I am using ng-show.
<div class="box-3" ng-show="Questions[1].SelectedOption === 'Yes'">
This works fine. But I feel the ng-show should have been mapped to a property or a method so that the logic resides in the controller and not in the html.
I would appreciate any comments on my above approach or any thoughts on how to have this logic moved to controller. Questions are not loaded initially. There is a button click on which the question loads and from that time I want the div to respond to the answer of the
second question. Till the question loads, the div is hidden.
i am trying to do orderBy using dropdown value, but its not working :(
CODE:
var app = angular.module('myApp', []);
app.controller('myCtrl', function ($scope) {
$scope.datas = [{
"id": "1",
"name": "name area 1"
}, {
"id": "2",
"name": "name area 2"
}, {
"id": "3",
"name": "name area 3"
}, {
"id": "4",
"name": "name area 4"
}];
$scope.dropdown = [{
"title": "Newest first",
"value": "true"
}, {
"title": "Oldest first",
"value": "reverse"
}];
});
HTML:
<div ng-app="myApp">
<div ng-controller="myCtrl">
<ul ng-repeat="rows in datas | orderBy: 'id':orderByData">
<li>{{rows.id}} : {{rows.name}}</li>
</ul>
<select ng-model="orderByData" ng-options="x.value as x.title for x in dropdown"></select>
</div>
</div>
DEOM JS BIN
Why you use reverse?
Please use false instead reverse and it should work fine.
$scope.dropdown = [{
"title": "Newest first",
"value": "true"
}, {
"title": "Oldest first",
"value": "false"
}];
You don't need reverse parameter here. Instead you can do something like this:
<ul ng-repeat="rows in datas | orderBy: getSort()">
<li>{{rows.id}} : {{rows.name}}</li>
</ul>
Where getSort is defined as:
$scope.getSort = function() {
return $scope.orderByData ? 'id' : '-id';
};
Basically you want sort part to look like orderBy: 'id' or orderBy: '-id'.
Demo: http://jsbin.com/pepureta/1/edit?html,js,output