How do I access ng-show directive with ng-click? AngularJS - javascript

I just started learning so I'm creating a todo app.
I'm trying to show a div when I click on the edit button to edit my task.
this is my html
<div ng-controller='TasksCtrl'>
<div ng-repeat='(key, task) in tasksList' class='task-list'>
<div class='easy'>
<div class='div-list-style'></div>
<div id='task-{{key}}' style='cursor:pointer;z-index:5'
ng-click='editTask()' data-key='{{key}}' class='options
pull-right glyphicon glyphicon-pencil'>
</div>
<div class='task-desc' ng-bind='task.description'></div>
<div ng-hide='taskEdit = true'>FORM</div>
</div>
</div>
</div
This is my controller
todoApp.controller('TasksCtrl',['$scope', 'saveTaskService', function($scope, saveTaskService){
$scope.editTask= function(){
todoApp.directive('taskEdit', function(){
return function(scope, element){
//so I guess over here I need do ngHide = 'false' ? //
alert(element.attr('data-key'));
};
});
};
}]);

Here is a quick solution, you have a scope variable called taskShow that will tell ng-hide when to show it, then on ng-click you will trigger a function that will toggle that value:
<div ng-controller='TasksCtrl'>
<div ng-repeat='(key, task) in tasksList' class='task-list'>
<div class='easy'>
<div class='div-list-style'></div>
<div id='task-{{key}}' style='cursor:pointer;z-index:5'
ng-click='toggleHide(key)' data-key='{{key}}' class='options
pull-right glyphicon glyphicon-pencil'>
</div>
<div class='task-desc' ng-bind='task.description'></div>
<div ng-show='taskShow[key]'>FORM</div>
</div>
</div>
</div>
Controller:
todoApp.controller('TasksCtrl',['$scope', 'saveTaskService', function($scope, saveTaskService){
$scope.taskShow = {};
$scope.toggleHide = function (key) {
$scope.taskShow[key] = !$scope.taskShow[key];
};
}]);
Edit: switched ng-hide to ng-show so the divs are hidden by default and only shown when the other is clicked.

Related

ng-change and ng-click not triggering events in controller

I'm trying to create a radio type button selection in AngularJS. Here is my code.
HTML code:
<!-- Page Content -->
<div id="page-wrapper">
<div class="container-fluid">
<h3 class="page-header">Create Products</h3>
<div class="media-list" data-toggle="buttons">
<label class="btn btn-default col-md-2 custom-thumbnail">
<input type="radio" ng-model="platformSel" ng-change="tileSelect(value)" value="win" name="platform-selection" id="win-tile" >
<i class="center-block fa fa-windows fa-5x"></i>
<span class="text-center">Windows</span>
</label>
<label class="btn btn-default col-md-offset-custom col-md-2 custom-thumbnail">
<input type="radio" ng-model="platformSel" ng-change="tileSelect(value)" value="mac" name="platform-selection" id="mac-tile">
<i class="center-block fa fa-apple fa-5x"></i>
<span class="text-center">MAC</span>
</label>
</div>
</div>
<!-- /.container-fluid -->
</div>
<!-- /#page-wrapper -->
Controller code:
(function() {
'use strict';
function config($routeProvider) {
$routeProvider
.when('/createProduct', {
templateUrl: 'app/components/createProduct/createProductView.html',
controller: 'createProductCtrlr'
});
}
function createProductCtrlr($scope, $rootScope, $location) {
$scope.platformSel = '';
$scope.tileSelect = function(target) {
console.log(target + " selected");
};
}
angular
.module('pacman')
.controller('createProductCtrlr', ['$scope', '$rootScope', '$location', createProductCtrlr])
.config(['$routeProvider', config]);
})();
I don't see any call happening in 'tileSelect' function. I have no clue why.
Any help is appreciated. I'm new to Angular JS.
Is there any error in JavaScript console? As mentioned before you are missing ng-app and ng-controller directives.
<div id="page-wrapper" ng-app="pacman" ng-controller="createProductCtrlr">
The rest of the code almost correct but since you bind the radio to a model variable there is no need for passing argument in ng-change function.
$scope.tileSelect = function() {
console.log($scope.platformSel + " selected");
};
Check this fiddle
Debugging and fixing stuff is real hard. Not as simple as writing code from scratch.
The reason being is, 'data-toggle=buttons' just toggles the bootstrap UI and doesnt make any function calls. Remove the line from html line where class="media-list" and it works.
Answer:
data-toggle="buttons" just toggles the twin button group. Doesnt allow to make function calls.

Angular, share directive template between click functions

I have a directive which, when called, passes in a controller and an array.
In the controller I pass in, there is an object I want to loop over.
my html looks like this:
<div class="row">
<div class="col-md-6">
<div class="jumbotron" ng-controller="protocolCtrl as pctrl">
<button type="button" id="protocol" class="btn btn-primary btn-lg" ng-click="pctrl.getUpdatedList()"
data-toggle="modal" data-target="#modal">Modify Current Protocols</button>
<!--IN THIS MODAL YOU CAN ADD/CHANGE/DELETE DATA-->
<modal-directive list="pctrl" headers="['ID', 'Protocol']"></modal-directive>
</div>
</div>
<div class="col-md-6">
<div class="jumbotron" ng-controller="categoryCtrl as cctrl">
<button type="button" id="category" class="btn btn-primary btn-lg" ng-click="cctrl.getUpdatedList()"
data-toggle="modal" data-target="#modal">Modify Current Categories</button>
<!--IN THIS MODAL YOU CAN ADD/CHANGE/DELETE DATA-->
<modal-directive list="cctrl" headers="['ID', 'Category']"></modal-directive>
</div>
</div>
</div>
My problem is that no matter what I do, it's always the FIRST directive in the html that showes up, no matter what button I press.
My directive looks like this:
.directive('modalDirective', function(){
return {
restrict: 'E',
templateUrl: '/directives/modal-directive.html',
scope: {
list: '=',
headers: '='
},
link: function(scope, element, attrs){
console.log(attrs.list + ' | ' + attrs.headers);
}
};
});
My modal-directive.html looks like this:
<table class="table table-striped">
<thead>
<tr>
<th ng-repeat="h in headers"> {{ h }} </th>
</tr>
</thead>
<tbody>
<!-- Loop through -->
<tr ng-repeat="l in list.list">
<!--Access the actual values inside each of the objects in the array-->
<td ng-repeat="data in l"> {{ data }} </td>
<td>
<button type="button" class="btn btn-primary btn-sm"
data-toggle="modal">Edit</button>
</td>
<td>
<button type="button" class="btn btn-danger btn-sm" ng-click="list.removeData(l)"
data-dismiss="modal">Remove</button>
</td>
</tr>
</tbody>
</table>
Am I using isolated scopes wrong, or is it something else I need to change in order to make this work?
Update
Here is a fiddle, that demonstrates the problem.
No matter which button i click, it displays the same text in the modal body.
You don't really need two controllers and two directives to achieve this. Below is an example of how you can do this. Notice I moved the controller to the row instead of having separate controllers for each column. The controller myCtrl now handles the click functions which are bound to the buttons using the ng-click attribute. This then determines the which text should be placed where by calling there respective functions. IE proto() and cat()
Now this may not be ideal for your situation depending on how you plan on the architecture of your application. But it works for your current problem in terms of what you have provided.
HTML
<body ng-app="TM">
<div class="row" ng-controller="myCtrl as modalControl">
<div class="col-md-6">
<div class="jumbotron" >
<button
ng-click='proto()'
type="button" id="protocol"
class="btn btn-primary btn-lg"
data-toggle="modal"
data-target="#modal">Modify Current Protocols
</button>
</div>
</div>
<div class="col-md-6">
<div class="jumbotron">
<button
ng-click='cat()'
type="button"
id="category"
class="btn btn-primary btn-lg"
data-toggle="modal"
data-target="#modal">Modify Current Categories
</button>
</div>
</div>
<!--IN THIS MODAL YOU CAN ADD/CHANGE/DELETE DATA-->
<modal-directive ctrl="modalControl"></modal-directive>
</div>
</body>
Angular JS
angular.module('TM', [])
.controller('myCtrl', function($scope){
$scope.text ='default';
$scope.proto = function() {
this.text = 'Now looking at the protocol part'
}
$scope.cat = function() {
this.text = 'Now looking at the category part'
}
})
.directive('modalDirective', function(){
return {
restrict: 'E',
scope: true,
template: ['<div id="modal" class="modal fade" role="dialog">',
'<div class="modal-dialog">',
'<div class="modal-content">',
'<div class="modal-header">',
'<h4 class="modal-title">Modal Header</h4>',
'</div>',
'<div class="modal-body">',
'<p> {{ text }} </p>',
'</div>',
'<div class="modal-footer">',
'<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>',
'</div>',
'</div>',
'</div>',
'</div>'].join('')
}
});
Demo:
https://jsfiddle.net/DTcHh/10193/
UPDATE:
Okay, I took another look. And even though the above example works. I noticed that I have a few extra things that I didn't necessarily need. For example myCtrl as modalControl doesn't need the as modalControl part. Below is an updated example. I did this one with some different simplified markup.
HTML:
<body ng-app="TestApp">
<div ng-controller="myCtrl">
<button ng-click="one()">One</button>
<button ng-click="two()">Two</button>
<test-directive></test-directive>
</div>
</body>
Angular Example (without Isolated Scope)
angular.module('TestApp', [])
.controller('myCtrl', function($scope){
$scope.text ='default';
$scope.one = function() {
this.text = 'this is one'
}
$scope.two = function() {
this.text = 'this is two'
}
})
.directive('testDirective', function(){
return {
template: "<div id='test'>{{text}}</div>"
}
});
Demo 2:
https://jsfiddle.net/krishollenbeck/v8tczaea/12/
Note this..
restrict: 'E',
scope: true
Was also not needed because I am not using Isolated scope in this example. More info here https://docs.angularjs.org/guide/directive
Please check this JSFiddle.
The reason is that data-target value points to the DOM element id of the modal. If you fixed this id in the directive template, clicking on the button will always initiate the modal with id modal. So you need to make the modalId as another parameter of the directive.
By the way, you can pass a controller to a directive. Just like this JSFiddle:
angular.module('Joy', [])
.controller('MyCtrl', ['$scope', function ($scope) {
this.value = 'Joy';
}])
.directive('passMeContrller', [function () {
return {
restrict: 'A',
scope: {
ctrl: '=',
},
template: '<div>Value: {{ctrl.value}}</div>'
};
}]);
The HTML:
<div ng-app="Joy" ng-controller="MyCtrl as c">
<div pass-me-contrller ctrl="c"></div>
<hr>
<div ng-bind="c.value"></div>
</div>
Because the controller itself is just a JavaScript object.
Just a reminder: you are using protocolCtrl as pctrl, so you need to specify like this.list=....
If you want to pass in a function to the isolated scope, use &.
However, I suggest not to pass in the whole controller to a directive. A controller is designed to:
Set up the initial state of the $scope object.
Add behavior to the $scope object.
Controllers are not supposed to be reused. Usually there are many properties on the $scope, while some of them passed to the directive will not be used by it.

Reset data on click for a different controller

I have two divs - the first contains the second. The contained div has its own controller. When I click an icon button in the container, I change a variable which then affects the visibility of the contained div.
It looks like this:
<div ng-controller="BarController">
<div class="navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
<div class="col-lg-2 page-title">My Page</div>
<div class="col-lg-10">
<span class="actions">
<i class="fa fa-lg fa-download fa-inverse" tooltip="Download"
ng-click="showSecondaryBar=!showSecondaryBar"></i>
</span>
</div>
</div>
</div>
<div class="download navbar download-in download-out"
ng-class="{'myhidden': !showSecondaryBar}"
ng-cloak>
<div class="col-lg-offset-4 col-lg-4 form-inline form-group" ng-controller="TagsController">
<div class="download-label col-lg-6">
<label>Download by tags:</label>
</div>
<div class="download-tags col-lg-6">
<tags-input class="bootstrap" spellcheck="false" min-length="1" ng-model="tags" add-from-autocomplete-only="true">
<auto-complete source="loadTags($query)" min-length="1" load-on-down-arrow="true"
load-on-focus="true" max-results-to-show="5"
highlight-matched-text="false"></auto-complete>
</tags-input>
</div>
</div>
</div>
</div>
The <tags-input> is taken from ng-tags-input and I would like to reset the tags that were already typed to it whenever the icon button is clicked (which changes the visilibyt of the div that contains the ng-tags-input).
Problem is, because I have the TagsController which contains the data (tags) and this data is not visible in the BarController, I'm not sure how I can reset the tags array to become empty.
I thought of using a service but it fills like too much of a coupling. I would prefer to have a function in TagsController which is called upon click. But I can't figure out how to do it from another controller
You are right you have to use a service.
Why don't you use a broadcast as your TagsController is included in BarController?
You can include a scope.broadcast("Event") in BarController
Then a "on" listener on TagsController who will reset the tags array when "Event" Occur.
I would personnaly to this.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
You can use $broadcast on $rootScope to send an event to TagsController. So TagsController can receive this event by registering an event listener for it. See following example.
Refer to $rootScope API docs
angular.module('app',[])
.controller('ParentController', function($rootScope) {
var parentCtrl = this;
parentCtrl.someFlag = true;
parentCtrl.changeFlag = function() {
parentCtrl.someFlag = !parentCtrl.somFlag;
$rootScope.$broadcast('resettags', {'defaultTags': 'whatever_tag'});
}
})
.controller('ChildController', function($rootScope){
var childCtrl = this;
childCtrl.tags = "Some tags entered by user";
$rootScope.$on('resettags', function(event, args) {
childCtrl.tags = args.defaultTags;
});
});
.myHidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div id="main" ng-controller="ParentController as parentCtrl">
<button type="button" ng-click="parentCtrl.changeFlag()">Toggle</button>
<div ng-class="{'myHidden' : !parentCtrl.someFlag}">
<div ng-controller="ChildController as childCtrl">
<h1>{{childCtrl.tags}}</h1>
</div>
</div>
</div>
</div>

How to dynamically update view in AngularJS

I have 2 div elements as following and I want to show only one of them based on the doStuff() function being called in the controller when an anchor element is clicked.
<div ng-controller='myController'>
<div ng-show="{{states['currentState'] == 'A'}}">
//displaying this div if the currentState is A
<a ng-click="doStuff('B')">Do stuff and show B</a>
</div>
<div ng-show="{{states['currentState'] == 'B'}}">
//displaying this div if the currentState is B
</div>
</div>
Following is the controller code:
myApp.controller('myController', ['$scope', function($scope) {
var states = ['A', 'B'];
$scope.states = states;
$scope.states['currentState'] = $scope.states['currentState'] || 'A';
$scope.doStuff = function(stateToShow) {
//doing stuff
$scope.states['currentState'] = stateToShow;
};
}]);
The code above doesn't work as the state remains 'A' even after clicking the Do stuff and show B anchor element.
Could somebody help me understand why is it not working?
Edit
app.js
//...
.state('home', {
url: '/',
views: {
'': { templateUrl: 'partials/index.html' },
'myView#home': {
templateUrl: 'partials/myView.html',
controller: 'VehicleController'
}
//other named ui views
}
})
//...
index.html
<div class="main">
<div class="container">
<div class="row margin-bottom-40">
<div class="col-md-12 col-sm-12">
<div class="content-page">
<div class="row">
<div ui-view="myView"></div>
<!-- other named ui-views -->
</div>
</div>
</div>
</div>
</div>
</div>
myView.html
<div ng-controller='myController'>
<div ng-show="states['currentState'] == 'A'">
//displaying this div if the currentState is A
<a ng-click="doStuff('B')">Do stuff and show B</a>
</div>
<div ng-show="states['currentState'] == 'B'">
//displaying this div if the currentState is B
</div>
</div>
It is updating the scope. But possibly the issue is with the ng-show you are setting a string by using "{{notation}}" which becomes truthy always (even if it is "true" or "false"), just use the expression directly.
Change
<div ng-show="{{states['currentState'] == 'A'}}">
to
<div ng-show="states.currentState === 'A'">
Demo
From Doc:-
ngShow expression - If the expression is truthy then the element is shown or hidden respectively.
You are very close. The reason it is not working is the attribute "ng-show" does not need the "{{" "}}" notation to work.
I just built your code but took those off, and it is working as you described you wanted it to.
<div ng-show="states['currentState'] == 'A'">
//displaying this div if the currentState is A
<a ng-click="doStuff('B')">Do stuff and show B</a>
</div>
<div ng-show="states['currentState'] == 'B'">
//displaying this div if the currentState is B
</div>

Directive template with Input + ng-model = magic?

I'm quite frustrated and apologize in advance for poorly formulated question.
I've created derictive for simple list editing:
angular.module('myApp').
directive('variableList', function () {
return {
restrict: 'AE',
templateUrl: 'variableList.html',
replace: true,
scope: {
value: '='
},
controller: [
'$scope', '$element', '$attrs', '$transclude',
function($scope) {
$scope.removeListItem = function (index) {
$scope.value.splice(index, 1);
};
$scope.addListItem = function () {
$scope.value.push($scope.nextListItem);
$scope.nextListItem = null;
};
}
]
};
});
and template
<div class="variable-list">
<div class="variable-list-items">
<div class="row collapse variable-list-item" ng-repeat="(index, val) in value">
<div class="small-11 columns variable-list-item-value">
<input type="text" ng-model="val" />
</div>
<div class="small-1 columns">
<button class="button alert prefix no-margin icon-minus"
ng-click="removeListItem(index)"></button>
</div>
</div>
</div>
<div class="row collapse variable-list-controls">
<div class="small-11 columns">
<input type="text" ng-model="nextListItem" />
</div>
<div class="small-1 columns">
<button ng-class="{disabled: !nextListItem}"
ng-click="addListItem()"
class="button success prefix no-margin icon-plus"></button>
</div>
</div>
</div>
the important part of template if
<input type="text" ng-model="val" />
In the end I have quite working ui
But inputs for existings items doesnt work! Nothing happen when I try to edit them. Input for new item, add and remove buttons works as intended.
Any ideas?
Edit
I've tried to bind model like this
<input type="text" ng-model="value[key]" />
I was able to edit input but it caused even more magic, after first keypress input loses focus.
Found answer here https://github.com/angular/angular.js/issues/1267
Basically you have to have a . in ng-model or the revers data binding does not work on primitives.

Categories

Resources