I am using AngularJS.
I have the following template:
<div>
... html content ....
</div>
I want to wrap the html content with an anchor only if the url model is not empty. For example, if $scope.url = 'www.cnn.com' then I want:
<div>
<a ng-href="url">
... html content ....
</a>
</div>
And if $scope.url = '' then I want:
<div>
... html content ....
</div>
Is there any way to do it in AngularJS?
Eventually I did it with a directive:
app.directive('skipElement', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var skip = attrs.skipElement ? !scope.$eval(attrs.skipElement) : false;
if (skip) {
var parent = element.parent();
var children = element.children();
children.detach();
parent.append(children);
}
}
};
}]);
Try ng-switch:
http://docs.angularjs.org/api/ng.directive:ngSwitch
<div ng-switch="url.length">
<div ng-switch-when="0"> .. content .. </div>
<div ng-switch-default> <a ng-href="url"> .. content .. </a> </ANY>
</div>
Related
I am quite new to angular.
I am trying to manage a list of contacts to be able to select one to display some details on the side. I was able to do it without directives but then I wanted to use directives and be able to show which one is selected in the list.
With directives I am able to display the list but when I select a contact it doesn't show details anymore so the select is not working and I can't get it to work as those directives are making me crazy.
Here is contact.html:
<li><a href selected="selected" ng-click='selectContact(contact)' ng-transclude></a></li>
// Code goes here
var app = angular.module("contactList", []);
app.service("peopleService", function($http) {
this.getPeople = function() {
return $http.get('people.json');
};
});
app.controller("peopleController", function($scope, peopleService) {
$scope.selectedContact = {};
$scope.selectedContactImage = ""
$scope.showDetail = false;
peopleService.getPeople().then(function(response) {
$scope.people = response.data.People;
});
$scope.selectContact = function(contact) {
$scope.selectedContact = contact;
if (contact.img) {
$scope.selectedContactImage = contact.img;
}
$scope.showDetail = true;
};
});
app.directive("contactList", function(){
return{
restrict: 'EA',
replace: true,
transclude: true,
template: "<div ng-transclude></div>",
controller: function(){
this.gotOpened = function(selectedContact){
contacts.forEach(function(contact){
if(selectedContact != contact){
contact.selected = false;
}
});
};
}
};
});
app.directive("contact", function(){
return {
restrict: 'EA',
replace: true,
transclude: true,
require: '^?contactList',
scope: {selected: '='},
templateUrl: 'contact.html',
link: function(scope, element, attrs, contactListController){
scope.selected = false;
scope.selectContact = function selectContact(){
scope.selected = !scope.selected;
contactListController.gotOpened(scope);
};
}
};
});
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
<script data-require="angularjs#1.6.4" data-semver="1.6.4" src="https://code.angularjs.org/1.6.4/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="contactList">
<div ng-controller="peopleController">
<contact-list>
<contact class="contact" ng-repeat="contact in people">
{{contact.name}}
</contact>
</contact-list>
<div class="list">
<ul>
<li ng-repeat="p in people">
<a href ng-click='selectContact(p)'>{{p.name}}</a>
</li>
</ul>
</div>
<div class="detail" ng-show="showDetail">
<div class="detailimagewrapper">
<img class="detailimage" src="{{selectedContactImage}}">
</div>
<label>Rating</label>
<p>{{selectedContact.rating}}</p>
<label>Description</label>
<p>{{selectedContact.Description}}</p>
</div>
</div>
</body>
</html>
Looks like you are using transclude and replace here. I expect this is causing your anchor tag to be replaced by the content which your contact directive is wrapping. Try removing the ng-transclude attribute from the anchor tag and instead adding <ng-transclude></ng-transclude> within the anchor tag.
contact.html would become:
<li>
<a href selected="selected" ng-click='selectContact(contact)'>
<ng-transclude></ng-transclude>
</a>
</li>
I hava a directive already(appView) and that has some html to load through templateUrl. As of now, I need to add one more custom directive to the template that is being used by another directive(appView).
Please see my code below and it is not working as expected. Any help on this how i can make this work please?
View.html (template)
<div>
<div class="dragdrop" id="dropzone" dropzone> //here is my custom directive
<div class="fileUpload btn btn-primary">
<span>UPLOAD ASSETS</span>
<input id="dzFile" type="file" class="upload" />
</div>
</div>
</div>
angular js
var appModule = angular.module("Newapp", []);
appModule.directive("appView", appView);
function appView(){
var directive = {
restrict: 'E',
templateUrl: 'app/View.html'
};
return directive;
}
appModule.directive("dropzone", function(){ //This is added to the View.html as attribute(see above html code with **)
var directive = {
restrict: 'A',
link: FullDragDrop
};
return directive;
});
function FullDragDrop(){
console.log("soemthing goes here");
}
How can I make this possible Please?
This code works for me.
Make sure templateUrl: 'app/View.html' exists
<script>
var appModule = angular.module("Newapp", []);
appModule.directive("appView", appView);
function appView(){
var directive = {
restrict: 'E',
templateUrl: 'view.html'
};
return directive;
}
appModule.directive("dropzone", function(){ //This is added to the View.html as attribute(see above html code with **)
var directive = {
restrict: 'A',
link: FullDragDrop
};
return directive;
});
function FullDragDrop(){
console.log("soemthing goes here");
}
</script>
<script type="text/ng-template" id="view.html">
<div class="dragdrop" id="dropzone" dropzone> //here is my custom directive
<div class="fileUpload btn btn-primary">
<span>UPLOAD ASSETS</span>
<input id="dzFile" type="file" class="upload" />
</div>
</div>
</script>
<body>
<app-view></app-view>
</body>
in my app I defined a directive which implement a simple slider with a next/prev/goto methods.
The slider then is within an html snipet managed by another controller.
The problem is that the last slide contains a form, so if the submit is ok than I would like to go to the next slide.
In old javascript I would have passed a callback to the submit method in order to apply that callback.
I made the same thing. Is this the best / angular style way to do it?
Javascript (I omitted some detail):
.directive("sfCarousel", function() {
return {
scope: true,
restrict: 'A',
controller: function($scope) {
var slides = $scope.slides = [];
var currentIndex = $scope.currentIndex = -1;
$scope.next = function() {
//mynextfunction...
}
},
link: function(scope, element, attrs) {
console.log("sf-carousel");
}
}
})
.directive("sfCarouselItem", function() {
return {
scope: true,
require: '^sfCarousel',
link: function(scope, element, attrs, sfCarouselController) {
console.log("sf-carousel-item");
sfCarouselController.addSlide(scope);
}
}
})
.controller("mycontroller", ['$scope', function($scope) {
$scope.submit = function (callback) {
//if submit is ok then
callback.apply(null, []);
}
}])
HTML:
<div sf-carousel >
<div sf-carousel-item ng-class="{'active':active}" >
<div>my first slide</div>
<div sf-label="get-started.submit" ng-click="next()" ></div>
</div>
<div sf-carousel-item ng-class="{'active':active}" >
<form>
<!--here my form-->
<button type="submit" ng-click="submit(next)">submit and go</button>
</form>
</div>
<div sf-carousel-item ng-class="{'active':active}" >
<div>my last slide</div>
<!--other things-->
</div>
</div>
You can pass the function that you what to run on the parent controller.
// directive sfCarousel
return {
transclude: true,
template: '<div class="sf-carousel" ng-transclude></div>',
// ...
};
// directive sfCarouselItem
return {
transclude: true,
scope: {
func: '&',
// ...
},
template: '<div class="sf-carousel-item" ng-transclude></div>',
}
// controller html
<div sf-carousel >
<div sf-carousel-item ng-class="{'active':active}" >
<div>my first slide</div>
<div sf-label="get-started.submit" ng-click="next()" ></div>
</div>
<div sf-carousel-item func="next()" ng-class="{'active':active}" >
<form>
<!--here my form-->
<button type="submit" ng-click="func({})">submit and go</button>
</form>
</div>
<div sf-carousel-item ng-class="{'active':active}" >
<div>my last slide</div>
<!--other things-->
</div>
</div>
I have developed a transclude directive and I set it to use angularjs template script everything works fine but I still cannot access the bind data.
My code:
index.html
<div side-element="box" title="Links">
<ul>
<li>Link 1</li>
<li>Link 2</li>
</ul>
</div>
<script id="box" type="text/ng-template">
<div class="side-box">
<div class="content">
<h2 class="header">Box {{ title }}</h2>
<span class="content" ng-transclude></span>
</div>
</div>
</script>
<script id="ad" type="text/ng-template">
<div class="side-ad">
<div class="content">
<h2 class="header">AD {{ title }}</h2>
<span class="content" ng-transclude></span>
</div>
</div>
</script>
app.js:
angular.module('myApp.directives')
.directive('sideElement', function ($templateCache, $log) {
return {
scope: {
title: '#'
},
transclude: 'element',
link: function(scope, element, attrs, ctrl, transclude){
var template = $templateCache.get(attrs.sideElement);
var templateElement = angular.element(template);
$log.info(scope.title);//Output the title i put in the html which is (Links)
transclude(scope, function(clone){
element.after(templateElement.append(clone));
});
}
};
});
the scope inside the link function(....) displaies the correct title but it doesn't work in the html:
Box {{ title }}
Link 1
Link 2
I think I missed one thing but I can't figure it out, I need your help to complete the cycle.
Thanx in advance,
The template element that contains the angular binding expressions must be compiled first, and then linked. The compilation phase prepares the template, while the linking phase sets up your $watchers for your binding expressions.
Demo Here
Here is a compile function that should work:
.directive('sideElement', function ($templateCache, $compile, $log) {
return {
restrict: 'A',
transclude: true,
scope:'#',
compile: function(element, attrs) {
var template = $templateCache.get(attrs.sideElement);
var templateElement = angular.element(template);
element.append(templateElement);
return function(scope, element, attr, ctrl, transclude) {
$log.info(scope.title);
}
}
}
As in the title, I'm trying to set a class on a div on page load ( not on a click ) with angular ng-class but I have no clue how to or if it is possible. The div is wrapped in a module and controller where I was previously trying to set the variable with $scope.frontpage but it didn't work.
<div id="main" role="main" class="clearfix" data-ng-module="ValidationBoxModule" ng-controller="ValidationBoxClassController">
<div validation-id="dataValidationSummary" validation-summary ng-class="frontpage" ></div>
<asp:ContentPlaceHolder ID="MainContentPlaceHolder" runat="server"></asp:ContentPlaceHolder>
</div>
angular.module("ValidationBoxModule", []).controller("ValidationBoxClassController", ["$scope", function ($scope) {
$scope.frontpage = "";
($("#main").find(".sliderBox")) ? $scope.frontpage = "frontpage" : $scope.frontpage = "";
}]);
So is there a way to do it ?
What you're trying to do is not the angular way. As in: "don't do DOM manipulation in the controller". Instead use a directive, e.g:
function Ctrl($scope) {
$scope.frontpage = false;
}
angular.module('app', ['app.directives']);
angular.module('app.directives', []).directive('isFrontpage', function () {
return {
restrict: 'A',
link: function (scope, element) {
scope.frontpage = angular.element(element).find('#main .sliderBox').length > 0;
}
};
});
with:
<body ng-controller="Ctrl" is-frontpage>
<div id="main">
<div class="sliderBox"></div>
</div>
<div
validation-id="dataValidationSummary"
validation-summary
ng-class="{frontpage: frontpage}">
</div>
</body>
demo: http://jsbin.com/unihon/4/