Why doesn't ng-click work when ng-blur used? - javascript

I have used ng-click on div and it works as expected, but when I have used ng-blur on some other input, the ng-click on the div stops working.
Working code [addItem(item) is being called on click]
<div ng-controller="TestController">
<input type="text" ng-focus="show=true">
<div ng-show="show" class="choosecont">
Choose from selected
<div ng-repeat="item in allItems" ng-click="addItem(item)" class="choose">{{item}}</div>
</div>
<div class="chosencont">
Following are selected
<div ng-repeat="item in selectedItems" class="chosen">{{item}}</div>
</div>
</div>
Broken code [addItem(item) not being called]
<div ng-controller="TestController">
<input type="text" ng-focus="show=true" ng-blur="show=false">
<div ng-show="show" class="choosecont">
Choose from selected
<div ng-repeat="item in allItems" ng-click="addItem(item)" class="choose">{{item}}</div>
</div>
<div class="chosencont">
Following are selected
<div ng-repeat="item in selectedItems" class="chosen">{{item}}</div>
</div>
</div>
Related JS code
angular.module("myApp", [])
.controller("TestController", ["$scope", function($scope) {
$scope.allItems = ["A", "B", "C", "D", "E"];
$scope.selectedItems = [];
$scope.addItem = function(item) {
if ($scope.selectedItems.indexOf(item) == -1)
$scope.selectedItems.push(item);
}
}
]);
Here is plunkr http://plnkr.co/edit/eI5dvczO2E1Cp1SBPgQx?p=preview
Click on input which will bring dropdown. Clicking on dropdown adds item to selected list in one case but not in other case.
I have tried to debug. scope is set correctly and it was accessible.

The click event fires after blur, so the list is being hidden before you are able to click it. The simple solution is to use mousedown event instead of click:
ng-mousedown="addItem(item)"
Here is an update to your plunkr: http://plnkr.co/edit/sPGIb1afCayS1UiP73Q0?p=preview

Related

AngularJS: How do you change a button and other elements within an ng-repeat with a click of said button?

Let's say that I have some code:
<div ng-app="myApp" ng-controller="myCtrl">
<div class="hey">
<div class="dude" ng-repeat="thing in things">
<button type="button" ng-click="doStuff()">click me</button>
<div ng-repeat="p in {{thing.parts}}">Part {{$index}}: {{p}}</div>
</div>
</div>
</div>
Now, let's say that I want to make it so that each "thing" in the "things" array has its own corresponding button. When I click on the button that corresponds to one particular "thing", the entries in the "parts" array (a property of a "thing") will be displayed and the text "click me" will change to "been clicked". When you click the button again, the entries of the parts array for that "thing" will not be displayed, and the text for the button will go back to saying "click me".
How exactly would I do this? I'm not quite sure how exactly to manipulate individual elements within an ng-repeat.
You need somewhere to store if a "thing" is active or not. You could either add an isActive property on thing or add an activeThing property on your VM.
For this example, put it on your VM.
Then put a div with an ng-if inside your outer ng-repeat, like so:
<div ng-app="myApp" ng-controller="myCtrl">
<div class="hey">
<div class="dude" ng-repeat="thing in things">
<div ng-if="thing !== activeThing">
<button type="button" ng-click="activeThing = thing">click me</button>
</div>
<div ng-if="thing === activeThing">
<button type="button" ng-click="activeThing = undefined">Clicked</button>
<div ng-repeat="p in {{thing.parts}}">Part {{$index}}: {{p}}</div>
</div>
</div>
</div>
</div>
You can track by id or track by index.
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function($scope) {
$scope.things = [{
id: 1,
title: "Thing Foo",
parts: ["a", "b", "c"]
},
{
id: 2,
title: "Thing Bar",
parts: ["d", "e", "f"]
}
];
$scope.doStuff = function(id, index) {
let thing
if (id) thing = $scope.things.find(t => t.id === id)
else thing = $scope.things[+index]
console.log(`${thing.title} clicked`);
thing.show = !thing.show;
if (!thing.show) return;
let c = thing.numClicks ? +thing.numClicks + 1 : 1;
thing.numClicks = c;
}
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div class="hey">
<div class="dude" ng-repeat="thing in things">
<button type="button" ng-click="doStuff(thing.id)">click me (id)</button>
<button type="button" ng-click="doStuff(false, $index)">click me (index)</button>
<div ng-show="thing.show">
<h3>Clicked {{thing.numClicks}} times</h3>
<div ng-repeat="p in thing.parts">Part {{$index}}: {{p}}</div>
</div>
<hr>
</div>
</div>
</div>

Change div content dynamically on ng-click AngularJS

I want to display some data and tables in the content div which depends on which category you choose on the left hand side navigation.
So if I change the category also the displayed content of the content div should change.
Here is my code on Plunkr.
But it seems that not even this simple example is working.
So I have two Questions:
1.) How can I fix this example code to run ?
But more important:
2.) Is there a better way to change the content div when you change the category ?
I removed 'this' elements from code and also changed ng-view to ng-show.
<div>
<div ng-show="showApple">{{content}}</div>
<div ng-show="showBanana">{{content}}</div>
<div ng-show="showOrange">{{content}}</div>
</div>
There was something wrong with that you named your div class "content" so I removed that also.
I am sure it isn't a perfect solution but now it works.
link to plnkr
To be honest your best bet is to use $states/views. With a data-ui-view on the content div and a data-ui-sref link on the button on your menu, you can easily switch out content. Take a look at the ui-router page to get a better understanding of it. With templates for each 'view' that your menu will click to, your code will not just be much easier to manage, but probably more understandable.
You can use ng-include to show your contents but you have to keep them in seperate files e.g contentForApple, contentForBanana and contentForOrange.
Here I can show you a little change in your div
<div class="content">
<div ng-show="MainCtrl.showApple" ng-include ="'contentForApple.html'"></div>
<div ng-show="MainCtrl.showBanana" ng-include = "'contentForBanana.html'"></div>
<div ng-show="MainCtrl.showOrange" ng-include = "'contentForOrange.html'"></div>
</div>
Hope this help you. Take one json array for category and data and get details of json data which index is clicked
<!DOCTYPE html>
<html>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp" ng-controller="MyController">
<div class="container">
<div class="row">
<div class="col-lg-3">
<ANY ng-repeat="x in category" ng-click="getData($index)">
{{x.category}}<br>
</ANY>
</div>
<div class="col-lg-6">
{{data}}
</div>
</div>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('MyController', function ($scope)
{
$scope.data = '';
$scope.category = [{category:'Apple',data:'Apple Data'},{category:'Banana',data:'Banana Data'},{category:'Orange',data:'Orange Data'}];
$scope.getData = function(index)
{
$scope.data = $scope.category[index]['data'];
}
});
</script>
</body>
</html>
I did it with simple ngif
1) Keep an Index of Page which needs to be is loaded now
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.pageIndex = 0;
/*
* Updates current Page index
*/
$scope.changeIndex= function(indexToChange){
$scope.pageIndex = indexToChange;
}
});
2) Load content based on selected index
<body ng-controller="MainCtrl">
<div class="mainframe">
<div class="navigation">
<ul class="list-group">
<li class="list-group-item" ng-click="changeIndex(0)">Home<span class="status-icon"></span></li>
<li class="list-group-item" ng-click="changeIndex(1)">Sign Up<span class="status-icon"></span></li>
<li class="list-group-item" ng-click="changeIndex(2)">About<span class="status-icon"></span></li>
</ul>
</div>
<div class="content">
<div ng-if="pageIndex == 0" ng-include ="'Home.html'"></div>
<div ng-if="pageIndex == 1" ng-include = "'SignUp.html'"></div>
<div ng-if="pageIndex == 2" ng-include = "'About.html'"></div>
</div>
</div>
Final Result:
https://embed.plnkr.co/ic0eY2vwiOnChN2ahrEt/

ng-class $event.stopPropagation() not working on parent in angular

I have 2 nested ng-repeats. The parent one adds a class to itself based on ng-click, however when I click the child it is still happening when I thought it shouldnt.
<div class="add-filter-tags" data-filter="{{f1}}" ng-class="{'tag_selected' : tag_selected }" ng-repeat="(f1,f2) in filters" ng-click="tag_selected = !tag_selected;">
<span>{{f1}}</span>
<div class="add-filter-tags sub-filter-tag" data-filter="{{f1_2}}" ng-click="$parent.$event.stopPropagation()" ng-repeat="(f1_2,f2_2) in filters[f1]" sibs ><span>{{f1_2}}</span></div>
</div>
EDIT: I have also tried it without $parent and its not working.
You should stop event propagation on the child so that it does not bubble up to the parent, there will be no $event object attached to the $parent as well. It is a special argument passed in with ng-click i.e
ng-click="$event.stopPropagation()"
angular.module('app', []).controller('ctrl', function($scope) {
});
.tag_selected {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="add-filter-tags" ng-class="{'tag_selected' : tag_selected }" ng-if="true" ng-click="tag_selected = !tag_selected;">
<span>Parent</span>
<div class="add-filter-tags sub-filter-tag" ng-click="$event.stopPropagation()" ng-if="true"><span>Child</span>
</div>
</div>
</div>

ng-Repeat in Angular.js Not iterating according to the items index in the json

I am trying to execute the below code where I'm trying use ng-repeat to iterate through a key:value pair.
But ng-repeat is not following the index instead of rendering the second key value its rendering the thrid index
HTML:
<div ng-app ng-controller="ItemsCtrl">
Type anything in the first box.
<div ng-repeat="(key, value) in item">
<input type="text" ng-model="item[key]" />
</div>
{{item | json}}
</div>
Javascript Controller:
function ItemsCtrl($scope) {
$scope.item = {
"1": "one",
"2": "two",
"10": "ten"};
}
Below is the jsfiddle link for the problem http://jsfiddle.net/nMjet/13/
Thanks #Blackhole.
Below the modified Code
HTML:
<div ng-app ng-controller="ItemsCtrl">
Type anything in the first box.
<div ng-repeat=" item in items">
<input type="text" ng-model="item[$indexxcdxdd]" />
</div>
{{item | json}}
</div>
Javascript Controller:
function ItemsCtrl($scope) {
$scope.items = ['one','two','ten'];
}

supplying AngularJS controller data

Assuming a controller is there to manipulate some data on the scope, what is the best practice to supply the controller with that data?
For example, if I have a list of items I might want a ListController to manipulate the list, and an ItemController to manipulate an individual item. But how do I give each ItemController an item to use?
In the case below, how would doSomethingToItem access the item. When nested in the ngRepeat the item is $scope.item, but in the selection view the item we want to manipulate is $scope.selection.
angular.module('MyApp', [])
.controller('ListController', function($scope, $http) {
$scope.list = $http.get(...);
$scope.selection = null;
})
.controller('ItemController', function($scope) {
$scope.doSomethingToItem = function() {
...
};
})
<div ng-controller="ListController">
<div ng-repeat="item in list" ng-click="selection = item">
<div ng-controller="ItemController">
<button ng-click="doSomethingToItem()">Do Something</button>
</div>
</div>
<div ng-show="selection"
<div ng-controller="ItemController">
<button ng-click="doSomethingToItem()">Do Something</button>
</div>
</div>
</div>
Isn't this a common structure, or is my thinking backwards?
You should understand that Angular would create n+1 ItemController in your case. N for items and 1 for the selection section.
To make passing the object that needs to be worked on easier you can change the method signature to
doSomethingToItem(item) and in html do
<button ng-click="doSomethingToItem(item)">Do Something</button> at both places.
Or else for the repeat case the item variable contains your object that you can access in ItemController
selection variable contains the reference to the select controller, which can be reference from the instance of the controller defined under selection section.
Update: The expression in ng-repeat and selection would differ
<button ng-click="doSomethingToItem(item)">Do Something</button>
and
<div ng-show="selection"
<div ng-controller="ItemController">
<button ng-click="doSomethingToItem(selection)">Do Something</button>
</div>
</div>
You could pass the item data model like this:
<div ng-init="instance = item" ng-controller="ItemController">
</div>
"instance" will be a reference to list array data model item in "ListController".
And you could access its property in your ItemController function closure:
.controller("ItemController", function($scope){
$scope.instance={};
$scope.doSomething = function(){
console.log($scope.instance.name);
}
$scope.$watch('instance',function(){
console.log("iitem changed");
},true);
});
I'm not quite sure what feature do you want to achieve in your "selection" implementation.
I think you want to implement a selected list and list item will be added to it when user clicked the list item. You could try to create a "selected list" model to control the selected list view if you want to add the selected item to a list.
ListController.js
.controller("ListController", function($scope){
$scope.selectedList = [];
$scope.addItem = function(item){
$scope.selectedList.push(item);
}
});
HTML
<div ng-repeat="selected in selectedList">
<div ng-init="instance = selected" ng-controller="ItemController">
<span>{{instance.name}}</span>
<button ng-click="doSomething()">selectedAction</button>
</div>
</div>
I wrote a simple multi-selected list example as following:
HTML
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Nested controller</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
<script src="js/nestedController.js"></script>
</head>
<body>
<div ng-controller="parentCtrl">
<h2>List</h2>
<div ng-repeat="item in list">
<input type="checkbox" ng-model="item.selected" ng-checked="item.selected"/>
<div ng-init="instance = item" ng-controller="childCtrl">
<span>{{instance.name}}</span>
<button ng-click="doSomething()">doSomething</button>
</div>
</div>
<h2>Selected</h2>
<div ng-repeat="selected in selectedList">
<div ng-init="instance = selected" ng-controller="childCtrl">
<span>{{instance.name}}</span>
<button ng-click="selectedAction()">selectedAction</button>
</div>
</div>
</div>
JS
angular.module("myApp",[])
.controller("parentCtrl",function($scope){
//test data
$scope.list = [{name:'item1',age:'12',selected:false},{name:'item2',age:'18',selected:false}];
//use model to control selected list view
$scope.selectedList = [];
//refresh the selected list model when the list checked stauts has been updated
$scope.$watch('list',function(){
console.log("parent controller detected change");
$scope.selectedList = [];
$scope.list.forEach(function(elem,index,array){
if(elem.selected===true){
$scope.selectedList.push(elem);
}
});
},true);
})
.controller("childCtrl",function($scope){
$scope.instance={}
$scope.doSomething = function(){
alert("I'm the item: "+$scope.instance.name);
}
$scope.selectedAction = function(){
alert("I'm the selected item: "+$scope.instance.name);
}
//could register a watcher to monitor the model status
$scope.$watch('instance',function(){
console.log("child controller detected change");
},true);
});
Here is the jsFiddle demo
Hope this is helpful.

Categories

Resources