I am using Yeoman so I don't know if it's causing this element directive to not work. So this html template is not showing. I tried using include to see if something was wrong with my code and include worked...so something is going wrong with my directive. Please HELP!
This is my index where I call the directive element:
<div class="announcements">
<div class="announcement-block">
<announcement-block-update></announcement-block-update>
</div>
</div>
This is my javascript:
(function() {
var app = angular.module('announcementApp', [
'ngAnimate',
'ngAria',
'ngCookies',
'ngMessages',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch'
]);
app.directive('announcementBlockUpdate',function(){
var announcementsObject = {
type: 'UPDATE',
announcement: 'DISA Maps are almost complete! Look foward to reporting out at the project share next week.'
};
return {
restrict: 'E',
templateUrl: '../views/update-announcement.html',
controller: function(){
this.announcement = announcementsObject;
},
controllerAs: 'announcement'
};
});
})();
This is my HTML template:
<div class="event-highlight update"></div>
<div class="wrap">
<div class="announcement-description">{{announcement.type}}</div>
<div class="announcement">{{announcement.announcement}}</div>
</div>
Your template has an extra closing </div> tag. Not sure if that's related to the problem you're having or not.
Otherwise, your code looks fine. You're initializing the app somewhere in your html, right?
<div class="announcements" ng-app="announcementApp">
TL;DR
Way below is a working code snippet based on what you posted.
Explanation
Instead of trying to specify the controllerAs property, set up two-way databinding between the main controller and the directive scope. This will allow you to simply update the controller (either from a service or resource) and the directive will also update automatically. This is thanks to isolate scopes, which you can learn more about here.
Code
(function() {
var app = angular.module('announcementApp', []);
app.directive('announcementBlockUpdate', function() {
return {
restrict: 'E',
template: '<div class="event-highlight update"></div><div class="wrap"><div class="announcement-description">{{announcement.type}}</div><div class="announcement">{{announcement.announcement}}</div></div>',
scope: {
announcement: '='
}
};
});
app.controller('announcementCtrl', function($scope) {
var announcementsObject = {
type: 'UPDATE',
announcement: 'DISA Maps are almost complete! Look foward to reporting out at the project share next week.'
};
// Change the announcement here...
$scope.announcement = announcementsObject;
});
})();
.announcements {
min-height: 100px;
border: 1px solid #000;
padding: 10px;
}
.announcement-block {
min-height: 20px;
border: 1px solid #333;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="announcementApp">
<div ng-controller="announcementCtrl">
<div class="announcements">
<div class="announcement-block">
<announcement-block-update announcement="announcement"></announcement-block-update>
</div>
</div>
</div>
</div>
Error in your html, the following:
<div class="wrap">
<div class="announcement-description">{{announcement.type}}</div>
<div class="announcement">{{announcement.announcement}}</div>
</div>
should be inside of
<div class="event-highlight update"></div>
Related
I'm trying to write a generic confirmation screen. I'd like to reuse it across a variety of different entities. Each entity has a different directive used to render it to screen.
Is there a way to write a template with a "directive-shaped hole" (my-directive below) that I can fill in programmatically?
<div>
Are you sure you want to blah?
<directive-from-scope value-from-scope="theValue" params-from-scope="theParams" />
</div>
I solve it with built-in ng-include directive.
Assume you have some directive with getTemplateUrl() function. You can put any login into this function but it should basically return you a string with the template URL.
Then you can do next thing in your directive template.
<div ng-include="directiveCtrl.getTemplateUrl()"></div>
Tag that you use doesn't matter, it can be any HTML tag, just choose one that works better for you.
Now in each template you can have whatever you want: directive, HTML with some controller on it, etc.
You can create directive with transclude:
angular.module('app', []).directive('myDirective', function() {
return {
restrict: 'E',
transclude: true,
template: `
<div class='borders'>
Are you sure you want to blah?
<div ng-transclude></div>
</div>
`
};
}).controller('ctrl', function($scope){
$scope.log = console.log;
$scope.title = 'Simple title';
});
.borders {
border-style: solid;
border-width: 1px 1px 1px 1px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='ctrl'>
<my-directive>
<ul>
<li>first</li>
<li>second</li>
</ul>
<input type='button' value='Log' ng-click="log(title)"/>
</my-directive>
<my-directive>
<h4>{{title}}</h4>
</my-directive>
</div>
I have a listing of blog posts and I want to be able to click on the title and have it dynamically redirect to the proper posting.
So far it works except when I click on the anchor tagged title it redirects to:
blog/#/post/:post
rather than
blog#/post/:post
I've tried to change the href to data-ng-href,
using target="_self"
and tried changing the href="#/post/{{post}}" and href="/post/{{post}}"
Routes:
(function(){
'use strict';
angular.module('ghpg')
.config(Config);
Config.$inject = ['$routeProvider'];
function Config($routeProvider){
$routeProvider
.when('/listing', {
templateUrl: '/angular/views/listing.client.view.html'
}).otherwise({
redirectTo:'/'
}).when('/post/:title',{
templateUrl: '/angular/views/post.client.view.html',
controller: 'postController',
controllerAs: 'post'
}).otherwise({
redirectTo:'/listing'
});
}
})();
Listing View:
(function(){
'use strict';
angular
.module('ghpg')
.controller('listingController', listingController);
listingController.$inject = ['$scope', 'blogContent'];//,'blogContent'] //, 'blogContent'];
////
function listingController($scope, blogContent){
var vm = this;
vm.articles = [];
grabData();
function grabData(){
return blogContent.getContent().then(function(data){
console.log(data.articles);
vm.articles = data.articles;
return vm.articles;
},function(err){
console.log(err);
vm.data = [];
});
}
}
})();
App.js:
(function(){
'use strict';
var dependencies = [
'ghpg',
'ngRoute'
];
angular.module('blogger', dependencies)
.config(Config);
Config.$inject = ['$locationProvider']
function Config($locationProvider){
$locationProvider.hashPrefix('!');
}
if (window.location.hash === '#_=_'){
window.location.hash = '#!';
}
//bootstrap angular
angular.element(document).ready(function(){
angular.bootstrap(document, ['ghpg']);
});
})();
LISTING VIEW:
<div class="container-fluid" data-ng-Controller="listingController as vm">
<h2> Listings </h2>
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-8">
<div class="post-listing" data-ng-repeat="post in vm.articles">
<h3 class="article-title"><a target="_self" data-ng-href="/blog#/post/{{post.title}}"> {{ post.title }} </a></h3>
<div class="article-container">
<div class="article-date"><span class="article-date">{{ post.date }}</span></div>
<div class="article-post>"><span class="article-content"> {{ post.content }} </span></div>
</div>
</div>
</div>
</div>
</div>
Having trouble where I went wrong. I strongly suspect that it's some small typo or something with my SPA location/locationProvider in app.js but it looks the same in my other apps, unless my eyes are fooling me (which could be totally happening!)
What I did for a fix was simply this:
changed the listing view's anchor:
<h3 class="article-title"><a target="_self" data-ng-href="/post/{{post.title}}"> {{ post.title }} </a></h3>
to include the /blog# portion in the href so that I have:
<h3 class="article-title"><a target="_self" data-ng-href="/blog#/post/{{post.title}}"> {{ post.title }} </a></h3>
Simple fix, cause only the blog portion or webpage of my website is the angularJS, everything else is not so the routing was not being called to route it until it saw /blog# as part of the app.
I have an angular app:
HTML
<body ng-controller="DashboardController as vm">
<div ng-controller="OneController as vm">
Number inside the controler: {{vm.number}}
</div>
<div ng-controller="TwoController as vm">
<me-dir></me-dir>
</div>
</body>
ANGULAR
angular.module('plunker', [])
angular.module('plunker').controller 'DashboardController', ()->
vm = #
angular.module('plunker').controller 'OneController', ()->
vm = #
vm.number = 7
angular.module('plunker').controller 'TwoController', ()->
vm = #
angular.module('plunker').directive 'meDir', ()->
return {
#scope: {} ???
#require ???
#link ???
template: "<strong>Got it!{{number}}</strong>"
}
How can I access the value vm.number from OneController and assign it to the scope inside of the directive?
Is it possible to do it using require and link field from directive?
Can you reference existing controller using require?
At the moment OneController isn't the parent of directive so require: '^ctrlName' doesn't work. I haven't found a lot of documentation about controller/require field. I know how to do it if I would have to pass it in using attributes and stuff. The question is strictly about require link controller directive fields.
Plunker link
Use a service to share data across components
Very simple service upgrade to your code with data shared between controller and directive through the service
angular.module('plunker').service 'SharedService', ()->
vm = #
vm.number=7
angular.module('plunker').controller 'OneController', (SharedService)->
vm = #
vm.number = SharedService.number
angular.module('plunker').directive 'meDir', (SharedService)->
return {
scope:{}
controllerAs:'dir'
controller: ()->
vm = #
vm.number = SharedService.number
template: "<strong>Got it!{{dir.number}}</strong>"
}
DEMO
EDIT 2
var app = angular.module("test", []);
app.controller("Ctrl1", function($scope) {
$scope.name = "Harry Potter";
});
app.controller("Ctrl2", function($scope) {
$scope.any = "Any"
});
app.directive("myDirective", function($compile) {
return {
restrict: "EA",
scope: true,
link : function(scope, element, attr) {
var scopeCtrlOne = angular.element('[ng-controller="Ctrl1"]').scope();
angular.element(element).append($compile(
"<div>Your name is : {{name}}</div>" +
"Change your name : <input type='text' ng-model='name' />")(scopeCtrlOne)
);
}
};
});
h2 {
cursor: pointer;
}
.directive {
border: 5px solid #F5BF6E;
;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="Ctrl1">
<h2 ng-click="reverseName()"> {{name}}, CTRL ONE</h2>
<div ng-controller="Ctrl2">
<h2 ng-click="reverseName()"> {{any}}, CTRL TWO</h2>
<div my-directive class='directive'></div>
</div>
</div>
</div>
EDIT 1
Look this. For details: http://www.undefinednull.com/2014/02/11/mastering-the-scope-of-a-directive-in-angularjs/
var app = angular.module("test",[]);
app.controller("Ctrl1",function($scope){
$scope.name = "Harry";
$scope.reverseName = function(){
$scope.name = $scope.name.split('').reverse().join('');
};
});
app.directive("myDirective", function(){
return {
restrict: "EA",
scope: true,
template: "<div>Your name is : {{name}}</div>"+
"Change your name : <input type='text' ng-model='name' />"
};
});
h2 {
cursor: pointer;
}
.directive {
border: 5px solid #F5BF6E;;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="Ctrl1">
<h2 ng-click="reverseName()">Hey {{name}}, Click me to reverse your name</h2>
<div my-directive class='directive'></div>
</div>
</div>
I'm having some issues with an app I'm creating in Cordova (5.3.3) using ionic (1.6.5) and angular js and building for iOS and Android.
I have a menu item that when I click should load the next state with other menu items. However it seems like it loads the next state once without the animation, then loads the state again with the animation resulting in a "jerky" effect. It's best shown in a video I have uploaded here: https://www.youtube.com/watch?v=YCEQeqFyNl4&feature=youtu.be
I was wondering if anybody has an idea of what could be the issue here and where I should start looking, or if there are known bugs about this?
Any help would be appreciated!
// the controller
.controller('ProgramCtrl', ['$scope', 'FacProgram',
function($scope, FacProgram) {
$scope.refresh = function() {
FacProgram.refresh()
.finally(function() {
$scope.$broadcast('scroll.refreshComplete');
});
};
$scope.temp_articles = function() {
return FacProgram.all();
};
}
])
.controller('ProgramDetailCtrl', ['$scope', '$stateParams', 'FacProgram',
function($scope, $stateParams, FacProgram) {
$scope.art = FacProgram.get($stateParams.programId);
}
])
// The factory in a different js file:
.factory('FacProgram', ['$http', '$q', 'FacJson',
function($http, $q, FacJson) {
var temp_articles = [];
function findHeader(src, headTag, index) {
var head = $(src).find(headTag).get(0);
temp_articles[index].headlinethumb = head.textContent;
temp_articles[index].headline = head.textContent;
}
function refresh() {
var q = $q.defer();
... // A fucntion that get's URL's from .json file
////////////////////////////////////////////////////////////
angular.forEach(urls, function(URL, index) {
//add the articles to the dictionary
temp_articles.push({
inx: index,
img: img_logos[index]
});
$http.get(URL)
.then(function(sc) {
// The will parse the html looking for thumbnail text, main body text etc
var src = sc.data.substring(sc.data.indexOf('<html>'));
... // code that parses website for content etc
////////////////////////////////////////////////////////
q.resolve();
},
function() {
q.reject();
});
});
});
return q.promise
}
return {
all: function() {
return temp_articles;
},
get: function(programId) {
return temp_articles[programId];
},
refresh: function() {
console.log('DPG programs refresh triggered');
temp_articles = []; // a catch to prevent duplicates and to allow other templates to use without
//contamination
return refresh()
}
}
}]);
<!-- the start state for progams of the DPG -->
<ion-view>
<ion-content>
<div class="list">
<a class="item item-thumbnail-left item-icon-right item-text-wrap" ng-repeat="art in temp_articles()" href="#/program/{{$index}}">
<img ng-src="{{art.img}}">
<h2 class="padding-top" style="font-weight: 300;">{{art.headlinethumb}}</h2>
<i class="icon ion-chevron-right" style="font-size: 18px"></i>
</a>
</div>
</ion-content>
</ion-view>
<!-- the datailed view of the application -->
<ion-view>
<ion-content>
<div style="text-align: left; padding-top: 30px; padding-left: 20px; padding-right: 20px">
<h2 style="font-weight: 500; font-size: 17px">{{art.headline}}</h2>
</div>
<!--<p style="padding-left: 10px; font-size: 13px; font-weight: 300">Datum</p>-->
<div style="text-align: center">
<img style="max-height: 300px; max-width: 300px; width: auto;" ng-src="{{art.img}}">
</div>
<div class="padding" style="font-weight: 300">
<div ng-bind-html="art.text | hrefToJS"></div>
</div>
</ion-content>
</ion-view>
the same happened to me if you put your controller in app.js try removing it from there and only applying it in controller or viceversa.
your state in app.js should look like this:
.state('state-name', {
url: '/state-name',
templateUrl: "templates/walkthrough/state-name.html"
//Notice no controller here
})
I try to implement html5 drag and drop with angular.
The code is:
<div ondrop="drop(event)"></div>
And in the controller:
$scope.drop = function(e) { console.log('a drop') };
This leads to the error:
Uncaught ReferenceError: drop is not defined
Exchanging 'ondrop' with 'ng-click' makes it work, so there is nothing missing in the controller.
ondrop is a HTML attribute, therefore it expects the given function to be global, as opposed to angular directives such as ng-click which expect the callbacks to be published on the $scope.
You can use non angular events by connecting functions, that fire in that events to your scope. In this case:
ondrop='angular.element(document.getElementById("Id of element with ngController,or ngView(if you use router)")).scope().drop(event)'
Here I modified the drag and drop example from W3Schools:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<style>
#div1, #div2 {
float: left;
width: 100px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
</style>
<body ng-app="myApp">
<div data-ng-controller="myCtrl" id="myContrId">
<div id="div1" ondrop='angular.element(document.getElementById("myContrId")).scope().drop(event)' ondragover='angular.element(document.getElementById("myContrId")).scope().allowDrop(event)'>
<img src="https://diethelper.xyz/DHadmin/images/logo2w.png" draggable="true" ondragstart='angular.element(document.getElementById("myContrId")).scope().drag(event);' id="drag1" width="88" height="31">
</div>
<div id="div2" ondrop='angular.element(document.getElementById("myContrId")).scope().drop(event)' ondragover='angular.element(document.getElementById("myContrId")).scope().allowDrop(event)'></div>
</div>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.allowDrop = function(ev) {
ev.preventDefault();
}
$scope.drag = function(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
$scope.drop = function(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
});
</script>
</body>
</html>
ng-click is a directive defined by angular itself. ondrop, is as far as I'm aware not part of angular's standard library. You will need to define a new directive in order to get the functionality you want. I would recommend checking out this blog post
http://blog.parkji.co.uk/2013/08/11/native-drag-and-drop-in-angularjs.html