Angular loading template manualy and then concatenate with another one - angularjs

I need to load some template from path and concatenate with another one example:
(function (module) {
var modalDialog = function (modal) {
return function (item, template, header) {//template as parameter
var inlineTMp = "<div>inline template</div>";//this template
var concatTemplate = template + inlineTMp;//pseudo code
var modalInstance;
var options = {
template: concatTemplate,
controller: function () {
this.title = header || 'Dialog';
this.data = angular.copy(item);
this.noClicked = function() {
modalInstance.dismiss('cancel');
};
this.yesClicked = function (itemData) {
modalInstance.close(itemData);
};
},
controllerAs:"model"
};
modalInstance = modal.open(options);
return modalInstance.result;
}
}
module.factory("modalDialog", ['$modal', modalDialog]);
})(angular.module("common"));
so how do i download a template then concatenate with another and send to service.

Related

Angular Unknown provider. Netsted controllers

I cannot work out how to call a method in another angular controller.
On the webpage there is another angular app. I want to use some of the functionality from the other app. As soon as i add the other controller to my html I get this error when the page loads:
Unknown provider: documentsServiceProvider <- documentsService <- documentActionsController
My code:
angular.module('myApp', [])
.controller("documentActionsController", SomeNameSpace.DocumentActionsController)
.controller('myController', function ($scope) {
Markup
<div id="qms-part-docApp" ng-controller="myController" >
<tr ng-repeat="fileInfo in documentList track by $index">
<a ng-controller="documentActionsController" ng-click="addToFavorites()"></a></td>
I want to call a method on this documentActionsController (TypeScript compiled)
var Controllers;
(function (Controllers) {
var DocumentActionsController = (function (_super) {
__extends(DocumentActionsController, _super);
function DocumentActionsController($scope, documentsService, basketService, favoritesService) {
var _this = this;
_super.call(this, $scope);
this.$scope = $scope;
this.documentsService = documentsService;
this.basketService = basketService;
this.favoritesService = favoritesService;
this.init = function () {
_this.$scope.addToFavorites = _this.addToFavorites;
_this.$scope.removeFromFavorites = _this.removeFromFavorites;
_this.$scope.addToBasket = _this.addToBasket;
_this.$scope.removeFromBasket = _this.removeFromBasket;
_this.$scope.markAsRead = _this.markAsRead;
_this.$scope.isItInFavorites = _this.isItInFavorites;
_this.$scope.isItInBasket = _this.isItInBasket;
_this.$scope.isItRead = _this.isItRead;
};
this.addToFavorites = function (id, title, owner, url, icon, path) {
SomeNamespace.addToFavorites(id, title, owner, url, icon, path);
};
this.removeFromFavorites = function (id, path) {
SomeNamespace.removeFromFavorites(id, path);
};
this.addToBasket = function (id, title, owner, url, icon, filename) {
SomeNamespace.addToBasket(id, title, owner, url, icon, filename);
};
this.removeFromBasket = function (id) {
SomeNamespace.removeFromBasket(id);
};
this.markAsRead = function (id, version) {
SomeNamespace.markAsRead(id, version);
};
this.isItInFavorites = function (id) {
SomeNamespace.isItInFavorites(id);
};
this.isItInBasket = function (id) {
SomeNamespace.isItInBasket(id);
};
this.isItRead = function (id, version) {
SomeNamespace.isItRead(id, version);
};
this.init();
}
DocumentActionsController.$inject = [
"$scope",
"documentsService",
"basketService",
"favoritesService"
];
return DocumentActionsController;
Register services like this,
angular.module('myApp', [])
.service("documentsService", function(){
// write code
})
.service("basketService", function(){
// write your code
})
.service("favoritesService", function(){
// write your code
})
.controller("documentActionsController", SomeNameSpace.DocumentActionsController)
.controller('myController', function ($scope) {

angularjs bind to controller with isolated scope

I have a pretty simple directive and I want to use the bindToController option. So, I created my directive like this:
(function () {
'use strict';
angular.module('sapphire.directives').directive('list', list);
function list() {
return {
restrict: 'A',
template: '<div class="row flex-column" ng-class="{ \'spinner-dark\': controller.loading }" ng-include="controller.templateUrl" ng-if="controller.loading || controller.models.length"></div>',
controller: 'ListDirectiveController',
controllerAs: 'controller',
scope: true,
bindToController: {
method: '&list',
templateName: '#'
}
};
};
})();
And then I created my controller like this:
(function () {
'use strict';
angular.module('sapphire.directives').controller('ListDirectiveController', listDirectiveController);
listDirectiveController.$inject = ['ListDirectiveService', 'Selections'];
function listDirectiveController(broadcast, selections) {
var self = this;
console.log(self);
// Bindings
self.limit = 0;
self.total = 0;
self.loading = true;
self.templateUrl = 'app/directives/lists/list/' + (self.templateName || 'list-default') + '.html';
self.isSelected = selections.isSelected;
self.select = selections.select;
// Method binding
self.list = list;
init();
//////////////////////////////////////////////////
function init() {
list();
};
// Our list method
function list() {
// Set our initial limit
self.limit += 10;
self.loading = true;
// Get our items
return self.method({ limit: self.limit }).then(function (response) {
self.loading = false;
self.models = response;
self.total = response.length;
});
};
///////// ------ Removed for brevity ------ /////////
};
})();
When I use this directive I get an error stating:
self.method is not a function
which is why I am console.logging the controller to see what is bound to it. Surely enough, the method and templateName are missing.
I have tried a few ways to get this to work:
scope: {
method: '&list',
templateName: '#'
},
bindToController: true
or
scope: {},
bindToController: {
method: '&list',
templateName: '#'
}
but nothing seems to work. I can't get my isolated scope to be bound to my controller....
Does anyone know what I am doing wrong?
PS: I am using angular 1.6.4
To use the directive I do this:
<div class="invisible-container" list="controller.listUsers(limit)" template-name="users"></div>
Ok, so I figured this out. The scope is bound, but it isn't available straight away. I had to create an init method and invoke it from the directive. Only then was everything bound.
I did it like this:
(function () {
'use strict';
angular.module('sapphire.directives').directive('list', list);
function list() {
return {
restrict: 'A',
template: '<div class="row flex-column" ng-class="{ \'spinner-dark\': controller.loading }" ng-include="controller.templateUrl" ng-if="controller.loading || controller.models.length"></div>',
controller: 'ListDirectiveController',
controllerAs: 'controller',
scope: {
method: '&list',
templateName: '#'
},
bindToController: true,
link: function (scope, element, attrs, controller) {
controller.init();
}
};
};
})();
and the controller now looks like this:
(function () {
'use strict';
angular.module('sapphire.directives').controller('ListDirectiveController', listDirectiveController);
listDirectiveController.$inject = ['ListDirectiveService', 'Selections'];
function listDirectiveController(broadcast, selections) {
var self = this;
// Bindings
self.limit = 0;
self.total = 0;
self.loading = true;
self.isSelected = selections.isSelected;
self.select = selections.select;
// Method binding
self.init = init;
////////////////////////////////////////////////////
function init() {
list();
getTemplate();
bindEvents();
};
function bindEvents() {
broadcast.onPrepend(onPrepend);
broadcast.onRefresh(onRefresh);
};
function getTemplate() {
self.templateUrl = 'app/directives/lists/list/' + (self.templateName || 'list-default') + '.html';
};
function list() {
// Set our initial limit
self.limit += 10;
self.loading = true;
// Get our items
return self.method({ limit: self.limit }).then(function (response) {
self.loading = false;
self.models = response;
self.total = response.length;
});
};
function onPrepend(event, args) {
if (args && args.target && args.target === self.templateName) {
self.models.unshift(args.model);
}
};
function onRefresh(event, args) {
if (args && args.target && args.target === self.templateName) {
self.limit -= 10;
self.models = [];
list();
}
};
};
})();

Directive in ng-repeat not re-processing after updating the array

I have a directive which converts certain strings into links (/) tags. I use this directive inside an ng-repeat to add links to text within a list of s. However, I refresh this data from a server which overwrites the array of the ng-repeat. The list gets updated in the DOM but the text no longer has links in it as it did when processed by the directive. How do I make the directive reprocess the text to add links?
Relevant code below
Controller HTML
<div ng-repeat="post in posts track by $index" ng-if="!post.deleted">
<div class="post wrap" ng-click="openSinglePostView(post, $index)" >
<div class="post-desc" linkify="twitter" ng-bind="post.desc"></div>
</div>
</div>
Controller JS
$scope.posts = [];
function refresh(){
$http.get(Constants.GET_POSTS_URL, {params : paramObject})
.then(function (response){
$scope.posts = [];
for(var i = 0; i < response.data.resultsArray.length; i++){
var post = new PostFactory(response.data.resultsArray[i]);
$scope.posts.push(post);
}
});
}
refresh();
Directive code
angular.module('linkify').directive('linkify', ['$filter', '$timeout', 'linkify', function ($filter, $timeout, linkify) {
'use strict';
return {
//restrict: 'A',
link: function (scope, element, attrs) {
var type = attrs.linkify || 'normal';
$timeout(function () { element.html(linkify[type](element.html()));
});
}
};
}]);
and for reference, the directive uses these filters and factories
angular.module('linkify')
.filter('linkify', function (Constants) {
'use strict';
function linkify (_str, type) {
if (!_str) {
return;
}
var _text = _str.replace( /(?:https?\:\/\/|www\.)+(?![^\s]*?")([\w.,#?!^=%&:\/~+#-]*[\w#?!^=%&\/~+#-])?/ig, function(url) {
var wrap = document.createElement('div');
var anch = document.createElement('a');
anch.href = url;
anch.target = "_blank";
anch.innerHTML = url;
wrap.appendChild(anch);
return wrap.innerHTML;
});
// bugfix
if (!_text) {
return '';
}
// Twitter
if (type === 'twitter') {
_text = _text.replace(/(|\s)*#([\u00C0-\u1FFF\w]+)/g, '$1#$2');
_text = _text.replace(/(^|\s)*#([\u00C0-\u1FFF\w]+)/g, '$1#$2');
}
return _text;
}
//
return function (text, type) {
return linkify(text, type);
};
})
.factory('linkify', ['$filter', function ($filter) {
'use strict';
function _linkifyAsType (type) {
return function (str) {(type, str);
return $filter('linkify')(str, type);
};
}
return {
twitter: _linkifyAsType('twitter'),
icon: _linkifyAsType('icon'),
normal: _linkifyAsType()
};
}])
Could the track by $index be the problem? Have you tried without it?

Directive input value changing when calling directive multiple times

I have the following directive,
(function(){
angular.module("pulldownmodule")
.controller("pulldownCtrl",['pullDownServices','$scope',"multiselectDefaults","templates",function(pullDownServices,$scope,multiselectDefaults,templates){
//Local variables
_this = this;
var dropdownData = {};
var currentTemplate = {};
var firstTemplate;
//Validation function
function validateInput(){
console.log(_this.dropdownid);
if (_this.dropdownid) {
getPullDownData(_this.dropdownid,_this.filter);
}
//check if the dropdown ID is present
}
$scope.$watch('pulldownCtrl.dropdownid',function(newVal){
console.log(_this.dropdownid);
if (newVal) {
validateInput();
};
});
}])
.directive('pulldown', [function(){
return {
scope: {},
bindToController:{
dropdownid:"=",
filter:"=",
templatetype:"#"
},
controller:'pulldownCtrl',
controllerAs:'pulldownCtrl',
templateUrl: 'pulldown/html/dropDownDirective.html'
};
}]);
})()
I am calling the directive 2 times as follows
<div pulldown dropdownid="currentID" templatetype="template2" filter="customFilter"></div>
<div pulldown dropdownid="currentID2" templatetype="template2" filter="customFilter2"></div>
Passing the value of dropdownid in the controller as
$scope.currentID = 1;
$scope.currentID2 = 5;
The issue here is if i call the directive only 1 time everything works fine, but if i call it multiple times then i get the _this.dropdownid in $watch as the second directives value. Not sure what I'm doing wrong.
Probably i have to create a new instance using 'new'.
Directive HTML
Following is the major part of the directives HTML,
<select id="searchData" kendo-multi-select="pulldown" k-options="ddoptions" k-rebind="ddoptions" k-on-change="getChangevalue('searchData')"></select>
i'm using the kendo multiselect
As #hgoebl point out _this = this; it is kind of global (not application level) variable though you use in a function scope.
Use var _this = this;
//after assign "_this" is not accessible here
(function(){
//after assign "_this" is accessible here
angular.module("pulldownmodule")
.controller(...function(){
_this = this; //use var _this = this;
//...others code
});
}();
angular.module("pulldownmodule",[])
.controller("pulldownCtrl",['$scope',function($scope){
//Local variables
_this = this;
// Initialize your models here
$scope.currentID = '1';
$scope.currentID2 = '3';
var dropdownData = {};
var currentTemplate = {};
var firstTemplate;
//Validation function
function validateInput(){
console.log(_this.dropdownid);
if (_this.dropdownid) {
getPullDownData(_this.dropdownid,_this.filter);
}
//check if the dropdown ID is present
}
$scope.$watch('currentID', function (newVal) {
console.log($scope.currentID);
if (newVal) {
validateInput();
};
});
$scope.$watch('currentID2', function (newVal) {
console.log($scope.currentID2);
if (newVal) {
validateInput();
};
});
}])
.directive('pulldown', [function(){
return {
scope: {
dropdownid:"=",
filter:"=",
templatetype:"#"
},
template: '<select ng-model="dropdownid"> <option ng-repeat="a in [1,2,3,4,5]" value="{{a}}"> {{a}} </option> </select>',
link: function (scope,element, attr) {
scope.$watch("dropdownid", function (newVal) {
scope.dropdownid;
});
}
};
}]);

View doesn't get updated from Service

I am trying to display an object (songTitle) from my service. The initial state (tmp) is displayed. If I am changing the object in the service, the view doesnt get updated.
Js:
var party = angular.module("party", []);
party.run(function () {
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
});
party.service('PlayerService', function ($window) {
this.playlist = [
"https://www.youtube.com/watch?v=fnW2uLwHAas",
"https://www.youtube.com/watch?v=iPT8DA32U6U",
"https://www.youtube.com/watch?v=eGjEnfQl37s",
"https://www.youtube.com/watch?v=nFtTY2S20mI",
"https://www.youtube.com/watch?v=UmXQiPLoLTk",
"https://www.youtube.com/watch?v=PbVx85DS9zc",
"https://www.youtube.com/watch?v=ciidn3nEoiE",
"https://www.youtube.com/watch?v=sm0DgkBEnUI",
"https://www.youtube.com/watch?v=J2OCSWF7sAw",
"https://www.youtube.com/watch?v=y_-giRHtuv8",
"https://www.youtube.com/watch?v=iPT8DA32U6U",
"https://www.youtube.com/watch?v=eGjEnfQl37s",
"https://www.youtube.com/watch?v=nFtTY2S20mI",
"https://www.youtube.com/watch?v=UmXQiPLoLTk",
"https://www.youtube.com/watch?v=PbVx85DS9zc"
];
this.player = {};
this.pbTimer = null;
this.songTitle = "tmp";
$window.onYouTubeIframeAPIReady = function () {
this.player = new YT.Player('ytplayer', {
height: '100',
width: '100',
videoId: 'ciidn3nEoiE',
events: {
'onReady': onPlayerReady
}
});
}
function onPlayerReady() {
console.log("db ready");
songTitle = player.getVideoData().title;
console.log(songTitle);
}
this.playVideo = function (url) {
console.log("db playVideo " + url);
player.loadVideoById(url.split("watch\?v=")[1], 0, "large");
console.log(player);
}
});
party.controller("FrontController", function ($scope) {
$scope.front = {};
$scope.front.title = "PARTY";
});
party.controller("PartyController", ['$scope', 'PlayerService', function ($scope, PlayerService) {
$scope.party = {};
$scope.party.title = "PARTY";
Sortable.create(playlist, { /* options */ });
$scope.playlist = PlayerService.playlist;
$scope.playVideo = function (url) {
PlayerService.playVideo(url);
}
$scope.songTitle = PlayerService.songTitle;
}]);
HTML
<body ng-app="party">
<div ng-controller="PartyController" class="container-fluid">
...
<p id="playertitle">{{songTitle}}</p>
...
Log:
db ready
Blackmill Feat. Veela - Life (Full Version)
The problem is in your onPlayerReady function. The line songTitle = player.getVideoData().title; doesn't set songTitle on your service, but rather on the global scope, which is the window object. Simply using this.songTitle won't help either, because this doesn't refer to your service too in the scope of onPlayerReady.
The easiest solution would be to save a reference to your service outside of onPlayerReady and then use it to assign songTitle:
var self = this;
function onPlayerReady() {
console.log("db ready");
self.songTitle = player.getVideoData().title;
console.log(self.songTitle);
}
Still, this is not enough. Because you change songTitle from outside the Angular world (the Youtube player callbacks), you need to call $scope.$apply to notify Angular something has changed.
For that, you need to inject $rootScope into your service:
party.service('PlayerService', function ($window, $rootScope)
and change songTitle using $rootScope.$apply:
var self = this;
function onPlayerReady() {
console.log("db ready");
$rootScope.$apply(function() {
self.songTitle = player.getVideoData().title;
console.log(self.songTitle);
});
}

Resources