Use variable for the view without modifying the model - angularjs

I have an object with a list of items X inside, each X has list of Y and each Y has a list of Z.
I would like to hide the span when clicking the button. I can easily do that by adding a property "visible" to each of my object and ng-click="obj.visible = !obj.visible".
But this solution means modifying the object and I don't really want that.
Is there a better solution?
I tried to use track by or a kind of hashmap but without real success.
Should I modify the model and clear it later if I need to save it?
angular.module('myModule', []);
angular.module("myModule")
.controller("DemoCtrl", demoCtrl);
demoCtrl.$inject = ["$scope"];
//demoCtrl
function demoCtrl($scope) {
vm = this;
vm.xObjects = [
{ "xname" : "x1",
"Ys" : [{
"yname" : "y1",
"Zs" : [{ "zname" : "z1" },
{ "zname" : "z2" }]
},
{
"yname" : "y2",
"Zs" : [{ "zname" : "z3" },
{ "zname" : "z4" }]
}]
},
{ "xname" : "x2",
"Ys" : [{
"yname" : "y3",
"Zs" : [{ "zname" : "z5" },
{ "zname" : "z6" }]
},
{
"yname" : "y4",
"Zs" : [{ "zname" : "z7" },
{ "zname" : "z8" }]
}]
}
];
vm.addX = function(){
vm.xObjects.push({ "xname" : "foo", Ys : []});
}
vm.addY = function(x){
x.Ys.push({ "Yname" : "bar", Zs : []});
}
vm.addZ = function(y){
y.Zs.push({ "Zname" : "too"});
}
}
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body data-ng-app="myModule">
<div data-ng-controller="DemoCtrl as demoCtrl" >
<div data-ng-repeat="xobject in demoCtrl.xObjects">
<span data-ng-hide="">xobject.xname = {{xobject.xname}}</span>
<button data-ng-click="">collapse</button>
<div data-ng-repeat="yobject in xobject.Ys">
<span data-ng-hide="">- - -yobject.xname = {{yobject.yname}}</span>
<button data-ng-click="">collapse</button>
<div data-ng-repeat="zobject in yobject.Zs track by $index">
<span data-ng-hide="">- - -{{$index}}- - -zobject.xname = {{zobject.zname}}</span>
<button data-ng-click="">collapse</button>
</div>
- - - - - -<button data-ng-click="demoCtrl.addZ(yobject)">add Z </button>
</div>
- - -<button data-ng-click="demoCtrl.addY(xobject)">add Y </button>
</div>
<button data-ng-click="demoCtrl.addX()">add X </button>
</div>
</body>
</html>

You can do that by creating property named hidden in the controller scope. To hide nested element, you can use arrays.
HTML:
<div ng-controller="DemoCtrl">
<div ng-repeat="x in xs">
<span ng-hide="hidden == $index">{{ x.name }}</span>
<button ng-click="hide($index)">Collapse</button>
<div ng-repeat="y in x.ys">
<span ng-hide="hidden == [x.$index, $index]">{{ y.name }}</span>
<button ng-click="hide([x.$index, $index])">Collapse</button>
<div ng-repeat="z in y.zs">
<span ng-hide="hidden == [x.$index, y.$index, $index]">{{ z.name }}</span>
<button ng-click="hide([x.$index, y.$index, $index])">Collapse</button>
</div>
</div>
</div>
</div>
With this controller:
angular.module("app", [])
.controller("DemoCtrl", function($scope) {
$scope.xs = [...]; // Your data here
$scope.hidden = -1; // Nothing hidden yet
$scope.hide = function(object) {
$scope.hidden = object;
};
});

Related

angular radio button set checked

i have multiple radio button groups
i need to set one of each group (maybe none) as selected
datasource
html Code
<div class='row' ng-show="mk.selectedTypeAttributesID.length != 0">
<div class='col-xs-6 col-sm-6 col-md-6 col-lg-6' ng-repeat="att in selectedTypeAttributesID">
<div class="switch-field">
<div class="switch-title">{{att.name}}</div>
<div>
<input ng-repeat-start="val in att.Values" class="bttn-input" type="radio" id="switch_{{val.val}}" name="switch_{{att.id}}" value="{{val.val}}" ng-click="mk.AttChange(att.id,val.val)" />
<label ng-repeat-end class="bttn-input" for="switch_{{val.val}}">{{val.val}}</label>
</div>
</div>
</div>
</div>
i need to use the value of 'Selected' On the datasource to set the checkbox
source Update
You need to use ng-model to select the radio button..
Where ng-model holds the selected value as shown below.
$scope.options = [{Selected: false, val: "red"}, {Selected: true, val:"Black"}, {Selected: false, val:"Pink"}];
$scope.selected = undefined;
var findResult = $scope.options.find(function(x){ return x.Selected == true });
if(findResult){
$scope.selected = findResult.val;
}
Here's a JSFiddle
Edit: Since the sources of the checkboxes are dynamic then build a dynamic selection tree for modal to bind to..
Here's an example:
$scope.options = [{ 0 : [{Selected: false, val: "red"}, {Selected: true, val:"Black"}, {Selected: false, val:"Pink"}]}, { 1 : [{ Selected: false, val: "2" }, { Selected: true, val: "1" }]}];
$scope.choices = [];
for(var i = 0; i < Object.keys($scope.options).length; i++){
var keys = Object.keys($scope.options);
$scope.choices.push({ Id: keys[i], Value: $scope.options[i][keys[i]].find(function(x){ return x.Selected == true }).val });
}
JSFiddle
Are you looking for a solution like so?
var app = angular.module('myApp', []);
app.controller('MyController', function MyController($scope) {
$scope.selectedTypeAttributesID = [{
id: 1,
Values: [{
val: "red",
selected: ""
}, {
val: "green",
selected: ""
}, {
val: "blue",
selected: ""
}]
},
{
id: 2,
Values: [{
val: "1",
selected: ""
}, {
val: "2",
selected: ""
}, {
val: "3",
selected: ""
}]
}
];
$scope.setVal = function(att, index, val) {
for (var k of att.Values) {
k.selected = "";
}
att.Values[index].selected = val;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller='MyController' ng-app="myApp">
<div class='row'>
<div class='col-xs-6 col-sm-6 col-md-6 col-lg-6' ng-repeat="att in selectedTypeAttributesID">
<div class="switch-field">
<div class="switch-title">{{att.name}}</div>
<div>
<input ng-repeat-start="val in att.Values" class="bttn-input" type="radio" id="switch_{{val.val}}" name="switch_{{att.id}}" ng-value="val.val" ng-click="setVal(att, $index, val.val)" />
<label ng-repeat-end class="bttn-input" for="switch_{{val.val}}">{{val.val}}</label>
</div>
</div>
</div>
</div>
<pre>{{selectedTypeAttributesID | json}}</pre>
</div>

AngularJS : `Load more` button in each group of ng-repeat with many groups titles

I want to add load more button to the bottom of each group like the image here, and after clicking the button it shows rest of parts of the relevant group
where a,g are groups titles those have group property
In the snippet bellow, the code return only one load more button, and with no consideration of the group property.
var myApp = angular.module('myApp',[]);
myApp.controller('main', ['$scope', function($scope) {
$scope.test = "test";
$scope.filteredModules = [
{
"name":"a",
"group":"a"
},
{
"name":"b",
},
{
"name":"c",
},
{
"name":"c",
},
{
"name":"e",
},
{
"name":"f",
},
{
"name":"g",
"group":"g"
}
,{
"name":"h",
},
{
"name":"i",
},
{
"name":"j",
},
{
"name":"k",
}
,
{
"name":"l",
}
];
$scope.limit = 4;
$scope.loadMore = function() {
var increamented = $scope.limit + 4;
$scope.limit = increamented > $scope.filteredModules.length ? $scope.filteredModules.length : increamented;
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="main">
<div ng-repeat="node in filteredModules | limitTo:limit track by $index">
<div ng-if="!node.group">{{node.name}}</div>
<div ng-if="node.group" style="background-color:red">{{node.name}} </div>
</div>
<button ng-click="loadMore()">Load more</button>
</div>
</div>
Please try this snippet
var myApp = angular.module('myApp',[]);
myApp.controller('main', ['$scope', function($scope) {
$scope.filteredModules = {
"groups":
[
{
"title": "Alfreds Futterkiste",
"childs": ["child-1", "child-2", "child-3", "child-4", "child-5", "child-6","child-7", "child-8", "child-9"],
"limit": "3"
},
{
"title": "Ana Trujillo Emparedados y helados",
"childs": ["child-1", "child-2", "child-3", "child-4", "child-5", "child-6"],
"limit": "4"
},
{
"title": "Antonio Moreno Taquería",
"childs": ["child-1", "child-2", "child-3", "child-4", "child-5", "child-6"],
"limit": "3"
}
]
};
$scope.loadMore = function(index) {
$scope.filteredModules.groups[index].limit = parseInt($scope.filteredModules.groups[index].limit) + 3;
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="main">
<div ng-repeat="node in filteredModules.groups track by $index">
<div ng-if="node.title" style="background-color:red">{{node.title}}
</div>
<div ng-repeat="child in node.childs | limitTo: node.limit">
{{child}}
</div>
<br/>
<button ng-click="loadMore($index)" ng-hide="node.limit >= node.childs.length">Load more</button>
<br/><br/>
</div>
</div>
</div>

Angularjs Ng-repeat with search filter only works on 2nd character keyup

I have implemented basic Angularjs search filter but it only work when I enter 2nd character in input box.
<input type="text" ng-model="search" class="search-input" id="search-input"><div ng-repeat="x in publishList | filter:search"></div>
I have implemented the same and is working, not sure why it is not working for you.
How ever can you try this?
<input type="text" ng-model="search.scheduleName" class="search-input" id="search-input">
I have tried with the code and the array you've given and it works for me.
Could you create a jsfiddle or plnkr example illustrating the problem ?
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{ scheduleName : 'Forrest' },
{ scheduleName : 'Gump' },
{ scheduleName : 'saw' },
{ scheduleName : 'xmen' },
{ scheduleName : 'troy' }
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<input type="text" ng-model="ctrl.search"/>
<div ng-repeat="item in ctrl.items | filter : ctrl.search">
{{item.scheduleName}}
</div>
</div>
</div>
You can also filter by an object's property in the array by using any one of the two approaches given below.
Specifying the property to filter in the AngularJS built-in filter called filter.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{ id: 1, scheduleName : 'Forrest' },
{ id: 2, scheduleName : 'Gump' },
{ id: 3, scheduleName : 'saw' },
{ id: 4, scheduleName : 'xmen' },
{ id: 5, scheduleName : 'troy' }
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<input type="text" ng-model="ctrl.search"/>
<div ng-repeat="item in ctrl.items | filter : { scheduleName: ctrl.search }">
{{item.id}}. {{item.scheduleName}}
</div>
</div>
</div>
Specifying an object to be used to filter - this is more dynamic.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{ id: 1, scheduleName : 'Forrest' },
{ id: 2, scheduleName : 'Gump' },
{ id: 3, scheduleName : 'saw' },
{ id: 4, scheduleName : 'xmen' },
{ id: 5, scheduleName : 'troy' }
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<input type="text" ng-model="ctrl.search.scheduleName"/>
<div ng-repeat="item in ctrl.items | filter : ctrl.search">
{{item.id}}. {{item.scheduleName}}
</div>
</div>
</div>

binding data in ng-repeat angularjs

*This is my html file where i want to repeat chapters which is a array that looks like
My code gives binds the selected checked boxes only (Index values) to true. But i need the entire list of chapters and their i.d's to be retrieved on submit.
Cannot figure out how to iterate it on nested loops *
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<span ng-repeat="chapter in chapters">
<label><input type="checkbox" name="checkbox" value="{{chapter}} ng-model="escConfigForm.chapters[$index]" >{{chapter.name}}</label><br>
</span>
<input type="submit" id="save" value="Save" />
$scope.chapters = chapterService.getChapters($scope.isbn);
$scope.submit = function(escConfigForm) {
var postData = {
content_items: JSON.stringify({
"#context" : [],
"#graph" : [ {
"#type" : "ContentItemPlacement",
"placementOf" : {
"#type" : "LtiLink",
"text" : escConfigForm.examName,
"mediaType" : "application/vnd.ims.lti.v1.launch+json",
"title" : "Exam Study Center",
"custom" : {
"dueDate" : escConfigForm.examDueDate,
"targetScore" : escConfigForm.examTargetScore,
"chapters" : escConfigForm.chapters
},
"activityType" : "other",
"activityRefId" : $scope.escId
}
} ]
}),
data: $scope.data
};
postForm($scope.postUrl, postData);
var configData = {
"activityRefId" : $scope.escId,
"dueDate" : escConfigForm.examDueDate,
"targetScore" : escConfigForm.examTargetScore,
"chapters" : escConfigForm.chapters
};
console.log($scope.chapters);
JSON file:
[{"name":"Chapter 1: Negative Messages","id":"832115"},{"name":"Chapter 2: Physics","id":"832115"},...]
I would recommend maintaining a list of the selected objects in the controller.
using this post as referenece: How do I bind to list of checkbox values with AngularJS?
I created this fiddle: http://jsfiddle.net/ruwk5r0v/7/
<div ng-app="formExample">
<div ng-controller="ExampleController"> <span ng-repeat="chapter in chapters" ng-click="checkboxChange($index)" ng-checked="selection.indexOf($scope.chapters[$index]) > -1">
<input type="checkbox" name="checkbox" value="{{$index}}" />
{{chapter.name}}
<br>
</span>
<br>
<input type="submit" ng-click="submitForm()" id="save" value="Save" />
<div> <span ng-repeat="chapter in selection">
<span>
{{chapter.name}}
</span>
<br>
</div>
and the js:
angular.module('formExample', []).controller('ExampleController', ['$scope', function ($scope) {
$scope.chapters = [{
"name": "Chapter 1: Negative Messages",
"id": "832115"
}, {
"name": "Chapter 2: Physics",
"id": "832115"
}];
$scope.submitForm = function () {
console.log(selection);
}
$scope.selection = []
$scope.checkboxChange = function(index){
var chapter = $scope.chapters[index];
var idx = $scope.selection.indexOf(chapter);
if (idx > -1){
$scope.selection.splice(idx, 1);
} else {
$scope.selection.push(chapter);
}
}
}]);
here you can very easily implement your submit function, just use the new selection object.
This really should be moved into a directive, but don't have time to write that right now :P
Here I created a controller for the snippet, and added some data to $scope.chapters object, and it is displaying correctly. The values disappear when selected, but that is another issue.
angular.module('myApp', [])
.controller('myCtrl', ['$scope',
function($scope) {
$scope.chapters = [{
name: 'Chapter 1: Negative Messages',
id: "1",
isSelected: false
}, {
name: 'Chapter 2: Physics',
id: "2",
isSelected: false
}];
$scope.submitItems = function(chapters) {
alert(JSON.stringify(chapters));
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<span ng-repeat="chapter in chapters">
<input type="checkbox" name="checkbox" value="{{chapter}}"
ng-model="chapter.isSelected" />
{{chapter.name}}
</span>
<br>
<form ng-submit="submitItems(chapters)">
<input ng-model="chapters" type="submit" id="save" value="Save" />
</form>
</div>
</div>
Edit: Updated the code to reflect the OP needs.

How do I cancel drag between different lists when using angular-ui's sortable module

I am using angular-ui's sortable-ui module and am trying to raise a cancel so that the dragged items returns to it original location in the source list. Unfortunately I cannot get this working. Here is an example:
http://jsfiddle.net/Ej99f/1/
var myapp = angular.module('myapp', ['ui.sortable']);
myapp.controller('controller', function ($scope) {
$scope.list = ["1", "2", "3", "4", "5", "6"];
$scope.list2 = ["7", "8", "9"];
$scope.sortableOptions = {
update: function(e, ui) {
if (Number(ui.item.text()) === 6) {
ui.item.parent().sortable('cancel');
}
},
receive: function(e, ui) {
ui.sender.sortable('cancel');
ui.item.parent().sortable('cancel');
},
connectWith: ".group",
axis: 'y'
};
});
angular.bootstrap(document, ['myapp']);
Any help would be gratefully appreciated.
well, when it comes to angular, all roads lead to the data "the single source of truth". So update your model back to it's original state, before the move, and you're all set :)
example below has two lists, the first one being restricted for
its sorting (the update method)
and for sending an item (receive method on list 2)
the second list you can sort, and send items to list 1
(using foundation4 for css)
<div ng-app="test">
<div ng-controller="sortableTest">
<div class="small-4 columns panel">
<ul data-drop="true"
ui-sortable="sortable.options.list1" ng-model="sortable.model.list1">
<li ng-repeat="fruit in sortable.model.list1"
data-id="{{ fruit.id }}">{{ fruit.label }}</li>
</ul>
</div>
<div class="small-4 columns panel">
<ul data-drop="true"
ui-sortable="sortable.options.list2" ng-model="sortable.model.list2">
<li ng-repeat="element in sortable.model.list2"
data-id="{{ element.id }}">{{ element.label }}</li>
</ul>
</div>
<div class="clear"></div>
<br />
<span ng-repeat="fruit in sortable.model.list1">{{ fruit.label }} </span><br />
<span ng-repeat="element in sortable.model.list2">{{ element.label }} </span><br />
<span ng-repeat="fruit in sortable.oldData.list1">{{ fruit.label }} </span><br />
<span ng-repeat="element in sortable.oldData.list2">{{ element.label }} </span><br />
</div>
</div>
js:
var test = angular.module('test', ['ui.sortable']);
test.controller('sortableTest', function($scope, $timeout) {
$scope.sortable = {
model: {
list1: [{id: 1, label: 'apple'},{id: 2, label: 'orange'},{id: 3, label: 'pear'},{id: 4, label: 'banana'}],
list2: [{id: 5, label: 'earth'},{id: 6, label: 'wind'},{id: 7, label: 'fire'},{id: 8, label: 'water'}]
},
oldData: {
list1: [],
list2: []
},
options: {
list1: {
update: function(event, ui) {
console.debug('up-list1');
$scope.sortable.oldData.list1 = $scope.sortable.model.list1.slice(0);
$scope.sortable.oldData.list2 = $scope.sortable.model.list2.slice(0);
// DO NOT USE THIS! it messes up the data.
// ui.item.parent().sortable('cancel'); // <--- BUGGY!
// uncomment and check the span repeats..
$timeout(function(){
$scope.sortable.model.list1 = $scope.sortable.oldData.list1;
$scope.sortable.model.list2 = $scope.sortable.oldData.list2;
});
},
connectWith: 'ul'
},
list2: {
update: function(event, ui) {
console.debug('up-list2');
},
connectWith: 'ul',
receive: function(event, ui) {
console.debug('re-list2');
$timeout(function(){
$scope.sortable.model.list1 = $scope.sortable.oldData.list1;
$scope.sortable.model.list2 = $scope.sortable.oldData.list2;
});
}
}
}
};
});
you can of course use a service or something to store the old value. One can use ui.sender to differentiate the senders, if you have more that two..

Resources