Angular JS change property of controller for directive - angularjs

I am trying to change boolean property of my controller from directive. It is set to true, but when i set it to false it should display other html template. Her is my code:
Directive code:
app.directive('entityTaskList', function(){
return {
restrict: 'E',
templateUrl: 'views/task/taskList.html',
scope: {
taskItems: '='
},
bindToController: true,
controller: 'TasksCtrl as taskCtrl',
link: function(scope, element, attrs){
scope.openItem = function(){
console.log("Open Items");
var ctrl = scope.taskCtrl;
ctrl.newTask = false;
};
}
};
});
TaskCtrl code:
app.controller('TasksCtrl', ['$scope', 'TaskService', function ($scope, TaskService) {
// initialize function
this.newTask = true;
this.name = "Nedim";
this.templates = {
new: "views/task/addTask.html",
view: "views/task/viewTask.html"
};
// load all available tasks
TaskService.loadAllTasks().then(function (data) {
$scope.items = data.tasks;
});
$scope.$on('newTaskAdded', function(event, data){
$scope.items.concat(data.data);
});
return $scope.TasksCtrl = this;
}]);
taskList.html
<ul class="list-group">
<li ng-repeat="item in taskCtrl.taskItems" class="list-group-item">
<a ng-click="openItem()">
<span class="glyphicon glyphicon-list-alt" aria-hidden="true"> </span>
<span>{{item.name}}</span>
<span class="task-description">{{item.description}}</span>
</a>
</li>
</ul>
and task.html
<!-- Directive showing list of available tasks -->
<div class="container-fluid">
<div class="row">
<div class="col-sm-6">
<entity-task-list task-items="items"></entity-task-list>
</div>
<div class="col-sm-6" ng-controller="TaskDetailCtrl as taskDetailCtrl">
<!-- form for adding new task -->
<div ng-show="taskCtrl.newTask" ng-include="taskCtrl.templates.new"></div>
<!-- container for displaying existing tasks -->
<div ng-show="!taskCtrl.newTask" ng-include="taskCtrl.templates.view"></div>
</div>
</div>
</div>

If you change this:
// load all available tasks
TaskService.loadAllTasks().then(function (data) {
$scope.items = data.tasks;
});
To this(literally):
// load all available tasks
TaskService.loadAllTasks().then(function (data) {
this.items = data.tasks;
});
your code will work, this is due to you using the controllerAs syntax for TaskCtrl but not assigning it to this instead to the $scope

Related

Setting $location and then filtering with AngularJS

For the purposes of navigation, I'm trying to have a button that triggers a function.
This function must first:
-Redirect to #/
And then:
-Filter an ng-repeat that exists in this view.
This is what I've tried but no luck.
<li><a ng-click="shopsingle()">Shop</a></li>
And JS:
$scope.shopsingle = function(){
$location.path("/");
setTimeout(function () {
$scope.$apply(function(){
$scope.filterExpr = {"shop" : true};
console.log($scope.filterExpr);
});
}, 300);
};
It does redirect to the desired path, where a full ng-repeat list appears, but it won't apply the filter, and console also comes empty.
About the views and routing, I'm using the same template for 2 different views, and showing/hidding parts of if while watching the $routeParams:
.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "home.htm",
controller : "mainCtrl"
})
.when('/:name',
{
templateUrl:"home.htm",
controller:"mainCtrl"
})
.otherwise({redirectTo:'/'});
})
And the controller watch:
$scope.name = $routeParams.name;
$scope.$watch(function() { return $scope.name; }, function(newVal) {
if (!newVal){
$scope.single = false;
} else{
$scope.single = true
};
$scope.newname = newVal;
$scope.chosenexhibitor = $filter("filter")($scope.images, {'name':$scope.newname}, true);
}, true);
And the view:
<!-- MAIN PAGE -->
<div ng-hide="single" id="tiles" masonry='{ "transitionDuration" : "0.15s" , "itemSelector" : ".tile"}'>
<div masonry-tile ng-repeat="item in images | filter:filterExpr" class="tile col-xs-3 col-md-3">
<a href="#/{{item.name}}">
<img class="img-fluid" ng-src="img/{{item.link}}">
</a>
</div>
</div>
<!-- SINGLE PAGE -->
<div class="row flexing" ng-show="single">
<div class="col-md-12">
<h1>{{chosenexhibitor[0].name}}</h1>
<img ng-src="img/{{chosenexhibitor[0].link}}">
<a class="back" href="#/">Back</a>
</div>
</div>
What am I missing?

Reuse a view as a modal and non-modal (angularjs + bootstrap-ui)

I currently use views/foo.html as a normal view.
Say this view has this:
<p>Hello</p>
Now I want to reuse views/foo.html as the content of a modal, but I'd like to wrap it with this:
<div class="modal-header">
<h3 class="modal-title">Foo</h3>
</div>
<div class="modal-body">
<!-- I want to include views/foo.html in here -->
</div>
So the modal would look like this:
<div class="modal-header">
<h3 class="modal-title">Foo</h3>
</div>
<div class="modal-body">
<p>Hello</p>
</div>
The modal invoker is the following: (notice the comment)
$scope.openFooModal = function () {
var modalScope = $scope.$new();
var modalInstance = $uibModal.open({
templateUrl: 'views/foo.html', /* HERE I NEED TO WRAP IT */
controller: 'fooController',
scope: modalScope,
size: 'lg'
});
modalInstance.result.then(function (result) {
}, null);
};
What is the best solution?
Should I create a foo2.html ?
So at the end the comment made by JB Nizet worked as a start, but there was this issue:
Inject $uibModalInstance to a controllar not initiated by a $uibModal
This is what I did finally:
view in charge of opening the modal or displaying it as an ng-view:
<body ng-controller="indexController">
<ul>
<li>
Open as modal
</li>
<li>
Open as non modal
</li>
</ul>
<div ng-view=""></div> <!-- Used by routeProvider -->
</body>
...its controller
angular.module('myApp').controller('indexController', ['$scope','$uibModal', function($scope,$uibModal) {
$scope.openModal = function () {
var modalScope = $scope.$new();
var modalInstance = $uibModal.open({
templateUrl: 'foo-as-modal.html',
controller: 'fooController',
scope: modalScope
});
modalScope.modalInstance = modalInstance;
// ^ I'm giving the modal his own reference
// using the scope. Injecting wont work on
// the non-modal case!
modalInstance.result.then(function (result) {
}, null);
};
}]);
view to be reused as a modal or as a non-modal:
<p>Hello {{name}}</p>
its controller:
angular.module('myApp').controller('fooController', ['$scope', function($scope) {
// ^
// I'm not injecting
// uibModalInstance
// (this is important)
$scope.name = "John";
$scope.cancel = function () {
$scope.modalInstance.dismiss('cancel');
// ^ I can access the modalInstance by the $scope
};
}]);
view to be used as a modal (wrapper)
<div class="modal-header">
<h3 class="modal-title">I'm a modal</h3>
</div>
<div class="modal-body">
<ng-include src="'foo.html'"></ng-include> <!-- Credits to JB's comment -->
</div>
<div class="modal-footer">
<button class="btn btn-default" ng-click="cancel()">Close</button>
</div>
routeProvider
$routeProvider
.when('/nonmodal', {
templateUrl: 'foo.html',
controller: 'fooController'
})
Here is a plunkr: https://plnkr.co/edit/ZasHQhl6M5cCc9yaZTd5?p=info

Variable value not passing in a controller using directive with ng-class

I am referencing the value of the variable in a controller in an ng-class template but its not working.
here is the html directive template URl :
<div class="tooltip-anchor">
<div class=" tooltip-content ehub-body" ng-class="{ 'tooltip__content--disabled': tooltipContentValue}" ng-transclude>Tooltip content</div>
</div>
Here is where i am using the directive in the index page
<div style="text-align:center;">
<ehub-tooltip>Hello i am here, and i am her to stay</ehub-tooltip>over here
<ehub-tooltip>Be nice to people on your way up and they will be nice to you on your way down</ehub-tooltip>click me
</div>
And here is the directive:
in this directive i am creating a variable and setting it to false and also trying to use it in an ng-class attribute
(function (window) {
'use strict';
angular
.module('ehub.component.tooltip', [])
.controller('ehubTooltipCtrl', ['$scope', function ($scope) {
$scope.tooltipContentValue = false;
}])
.directive('ehubTooltip', ehubTooltip);
function ehubTooltip() {
var directive = {
controller: "ehubTooltipCtrl",
link: link,
transclude: true,
templateUrl: 'ehub-tooltip.html',
restrict: 'E'
};
return directive;
function link(scope, element, attrs) {
scope.keyupevt = function () {
if (event.keyCode === 27) {
$scope.tooltipContentValue = true;
}
}
}
}
})();
Try this working jsfiddle.
angular.module('ExampleApp', ['ngMessages'])
.controller('ExampleController', function($scope) {
})
.directive('ehubTooltip', function() {
var directive = {
link: link,
transclude: true,
template: '<div class="tooltip-anchor"><div class=" tooltip-content ehub-body" ng-class="{ \'tooltip__content--disabled\': tooltipContentValue}" ng-transclude>Tooltip content</div></div>',
restrict: 'E'
};
function link(scope, element, attrs) {
scope.tooltipContentValue = false;
scope.keyupevt = function() {
if (event.keyCode === 27) {
scope.tooltipContentValue = true;
}
}
}
return directive;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<div style="text-align:center;">
<a href="" ng-keyup="keyupevt()">
<ehub-tooltip>Hello i am here, and i am her to stay</ehub-tooltip>over here</a>
<a href="" ng-keyup="keyupevt()">
<ehub-tooltip>Be nice to people on your way up and they will be nice to you on your way down</ehub-tooltip>click me</a>
</div>
</div>
</div>

Angularjs change view template after link clicked

I am trying to change html template after link is clicked. Value is boolean, initial value is true and appropriate template is loaded, but when value changed to false new template is not loaded, I don't know the reason. When initial value of boolean is true other template is loaded successfully, but on method called not. Please, help.
Here is my code:
TaskCtrl
app.controller('TasksCtrl', ['$scope', 'TaskService', function ($scope, TaskService) {
// initialize function
var that = this;
that.newTask = true;
that.name = "My name is Nedim";
that.templates = {
new: "views/task/addTask.html",
view: "views/task/viewTask.html"
};
// load all available tasks
TaskService.loadAllTasks().then(function (data) {
that.items = data.tasks;
});
$scope.$on('newTaskAdded', function(event, data){
that.items.concat(data.data);
});
that.changeTaskView = function(){
that.newTask = false;
console.log("New task value: " + that.newTask);
};
return $scope.TasksCtrl = this;
}]);
task.html
<!-- Directive showing list of available tasks -->
<div class="container-fluid">
<div class="row">
<div class="col-sm-6">
<entity-task-list items="taskCtrl.items" openItem="taskCtrl.changeTaskView()"></entity-task-list>
</div>
<div class="col-sm-6" ng-controller="TaskDetailCtrl as taskDetailCtrl">
<!-- form for adding new task -->
<div ng-if="taskCtrl.newTask" ng-include="taskCtrl.templates.new"></div>
<!-- container for displaying existing tasks -->
<div ng-if="!taskCtrl.newTask" ng-include="taskCtrl.templates.view"></div>
</div>
</div>
entityList directive
app.directive('entityTaskList', function () {
return {
restrict: 'E',
templateUrl: 'views/task/taskList.html',
scope: {
items: '='
},
bindToController: true,
controller: 'TasksCtrl as taskCtrl',
link: function (scope, element, attrs) {
}
};
});
directive template
<ul class="list-group">
<li ng-repeat="item in taskCtrl.items" class="list-group-item">
<a ng-click="taskCtrl.changeTaskView()">
<span class="glyphicon glyphicon-list-alt" aria-hidden="true"> </span>
<span>{{item.name}}</span>
<span class="task-description">{{item.description}}</span>
</a>
</li>
{{taskCtrl.newTask}}
Without any plunker or JSFiddle I can't tell for sure, but it might be issue with ng-if. I'm thinking of two workarounds.
First that I think is better. Use only 1 ng-include and only change the template.
HTML:
<entity-task-list items="taskCtrl.items" openItem="taskCtrl.changeTaskView('view')"></entity-task-list>
...
<div ng-include="taskCtrl.currentTemplate"></div>
JS:
that.currentTemplate = that.templates.new;
...
that.changeTaskView = function(template) {
that.currentTemplate = that.templates[template];
};
Or if you don't like this solution, try with ng-show instead of ng-if. With ng-show the elements will be rendered with display: none; property when the page loads, while with ng-if they will be rendered when the passed value is true.
Hope this helps you.

Unable to make angular-formly work within a ng-template of an angular-ui-bootstrap modal

I am using angular-formly to build a form inside an angular-ui-bootstrap modal, the following code works when the form is placed outside the modal template but it doesn't when placed inside the ng-template, it just doesn't print the fields at all.
I believe this should work but I don't know how the life-cycle of angular-formly runs, so I am unable to identify how to make the fields show up inside my bootstrap modal template.
The issue is clearly related to the ng-template, it appears not to render the form even if the fields array is passed correctly.
var app = angular.module("demo", ['dndLists', 'ui.bootstrap', 'formly', 'formlyBootstrap']);
app.controller('ModalInstanceCtrl', function ($scope, $uibModalInstance, items, User) {
var vm = this;
vm.loadingData = User.getUserData().then(function(result) {
vm.model = result[0];
vm.fields = result[1];
vm.originalFields = angular.copy(vm.fields);
console.log(vm);
});
});
app.controller("AdvancedDemoController", function($scope, $uibModal){
$scope.modalOpen = function(event, index, item){
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: 'md',
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
});
In my view:
<!-- Template for a modal -->
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
<div ng-if="vm.loadingData.$$state.status === 0" style="margin:20px 0;font-size:2em">
<strong>Loading...</strong>
</div>
<div ng-if="vm.loadingData.$$status.state !== 0">
<form ng-submit="vm.onSubmit()" novalidate>
<formly-form model="vm.model" fields="vm.fields" form="vm.form">
<button type="submit" class="btn btn-primary submit-button">Submit</button>
</formly-form>
</form>
</div>
<ul>
<li ng-repeat="item in items">
{{ item }}
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</div>
</script>
Any ideas?
When calling $uibModal.open you need to specify controllerAs: 'vm' (that's what you're template assumes the controller is defined as).

Resources