Angular directive with dynamic content - angularjs

I have created an accordion toggle for ionic angular in this punkr.
What i intend to achieve is to translate it to an directive that can be used as follow, where the content is dynamic based on the html that user insert. It could be a form, a text or simply a button. How could it be done??
<custom-accordion title="Header 1">
Content 1
</custom-accordion>
<custom-accordion title="Header 2">
Text: <input type="text" style="background: grey;" /><br>
Number: <input type="number" style="background: grey;" /><br>
</custom-accordion>

You can create a directive for the accordion and then load the content dynamically based on a scope variable. You might have to create separate HTML files for the content that you desire. Here is a plunkr for the same.
Directive
angular.module('starter.directives', [])
.directive("dynamicAccordion", function() {
return {
restrict:"A/E",
scope: {
content: "#"
},
template:"<div ng-include=getContent()></div>",
link: function(scope) {
scope.getContent = function() {
return scope.content;
},
scope.toggleContent = function() {
scope.isShow = !scope.isShow;
},
scope.isShow = true;
}
}
});
HTML
<ion-view title="Dashboard">
<ion-content class="has-header padding">
<dynamic-accordion content="accordionbutton.html"></dynamic-accordion>
<dynamic-accordion content="accordionform.html"></dynamic-accordion>
</ion-content>
</ion-view>
EDIT
This plunkr exposes the model from each form to the controller.
Directive
angular.module('starter.directives', [])
.directive("dynamicAccordion", function() {
return {
restrict:"A/E",
scope: {
content: "#",
model: "="
},
template:"<div ng-include=getContent()></div>",
link: function(scope) {
scope.getContent = function() {
return scope.content;
},
scope.toggleContent = function() {
scope.isShow = !scope.isShow;
},
scope.isShow = true;
}
}
});
HTML
<form>
{{ form | json }}
<dynamic-accordion content="accordionbutton.html" model="model1"></dynamic-accordion>
<dynamic-accordion content="accordionform.html" model="model2"></dynamic-accordion>
</form>
<button ng-click="checkModel()">Check Model</button>
Controller
$scope.model1 = {
text: "Default - 1",
number: 0
};
$scope.model2 = {
text: "Default - 2",
number: 0
};
$scope.checkModel = function() {
console.log("Text_1 "+$scope.model1.text +" Number_1 "+$scope.model1.number);
console.log("Text_2 "+$scope.model2.text +" Number_2 "+$scope.model2.number);
}

Related

Is it possible to move/sort/reorder Angular UI Tabs with drag and drop?

It seems possible with a previous version of Angular UI (see here) but I tried with uib-tabset and it doesn't work. Any ideas?
This doesn't work:
<uib-tabset sortable-tab>
<uib-tab heading="Title 1">
Some text 1
</uib-tab>
<uib-tab heading="Title 2">
Some text 2
</uib-tab>
</uib-tabset>
PLUNK
It still works. You have to apply the directive. The directive in your example is not already built in to the ui. Here is a Plunker with it working with the new version.
In your HTML:
<uib-tabset>
<uib-tab sortable-tab ng-repeat="tab in data.tabs" heading="{{tab.title}}" active="tab.active" disabled="tab.disabled">
<p>{{tab.content}}</p>
</uib-tab>
<uib-tab disabled="true">
<uib-tab-heading>
<i class="glyphicon glyphicon-plus"></i>
</uib-tab-heading>
</uib-tab>
</uib-tabset>
You have to include the directive as well in your Controller:
app.directive('sortableTab', function($timeout, $document) {
return {
link: function(scope, element, attrs, controller) {
// Attempt to integrate with ngRepeat
// https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L211
var match = attrs.ngRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
var tabs;
scope.$watch(match[2], function(newTabs) {
tabs = newTabs;
});
var index = scope.$index;
scope.$watch('$index', function(newIndex) {
index = newIndex;
});
attrs.$set('draggable', true);
// Wrapped in $apply so Angular reacts to changes
var wrappedListeners = {
// On item being dragged
dragstart: function(e) {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.dropEffect = 'move';
e.dataTransfer.setData('application/json', index);
element.addClass('dragging');
},
dragend: function(e) {
//e.stopPropagation();
element.removeClass('dragging');
},
// On item being dragged over / dropped onto
dragenter: function(e) {
},
dragleave: function(e) {
element.removeClass('hover');
},
drop: function(e) {
e.preventDefault();
e.stopPropagation();
var sourceIndex = e.dataTransfer.getData('application/json');
move(sourceIndex, index);
element.removeClass('hover');
}
};
// For performance purposes, do not
// call $apply for these
var unwrappedListeners = {
dragover: function(e) {
e.preventDefault();
element.addClass('hover');
},
/* Use .hover instead of :hover. :hover doesn't play well with
moving DOM from under mouse when hovered */
mouseenter: function() {
element.addClass('hover');
},
mouseleave: function() {
element.removeClass('hover');
}
};
angular.forEach(wrappedListeners, function(listener, event) {
element.on(event, wrap(listener));
});
angular.forEach(unwrappedListeners, function(listener, event) {
element.on(event, listener);
});
function wrap(fn) {
return function(e) {
scope.$apply(function() {
fn(e);
});
};
}
function move(fromIndex, toIndex) {
// http://stackoverflow.com/a/7180095/1319998
tabs.splice(toIndex, 0, tabs.splice(fromIndex, 1)[0]);
};
}
}
});
That directive also uses ng-repeat for the tabs the tabs are dynamic:
$scope.data = [];
$scope.data.tabs = [
{ title:'Dynamic Title 1', content:'Dynamic content 1', active:true},
{ title:'Dynamic Title 2', content:'Dynamic content 2'},
{ title:'Dynamic Title 3', content:'Dynamic content 3'}
];

Angular ng-if with Kendo UI autocomplete issue

I've just created an autocomplete Kendo input field inside a div which has to be controlled by a ng-if, because it has to be shown only to a particular category of users.
But I finally get rendered on my browser only a normal input field with no autocomplete properties.
If I remove the ng-if directive or even if I transform it to ng-show it works properly.
This is my HTML:
<div ng-if="utenteProfilo=='PB'">
<label for="PB" class="col-sm-2 control-label">PB</label>
<div class="col-sm-4">
<input ng-model="codPB" class="cento" id="codPB" />
<input type="hidden" id="cognomePb" name="cognomePb" />
<input type="hidden" id="nomePb" name="nomePb" />
</div>
</div>
This is my JS:
$("#codPB").kendoAutoComplete({
placeholder: "Scegliere un PB...",
dataTextField: 'PBanker',
filter: "contains",
autoBind: false,
minLength: 3,
headerTemplate: '<div class="dropdown-header k-widget k-header">' +
'<span>Cognome</span>' +
'<span>Nome</span>' +
'</div>',
template: '<span class="k-state-default" ></span>' +
'<span class="k-state-default"><h6 data-recordCognomePB="#= cognome #" data-recordNomePB="#= nome #">#: data.cognome # #: data.nome #</h6></span>',
select: function(e) {
var cognomePb = e.item.find('h6').attr('data-recordCognomePB');
var nomePb = e.item.find('h6').attr('data-recordNomePB');
$('#cognomePb').val(cognomePb);
$('#nomePb').val(nomePb);
},
filtering: function(e) {
$('#cognomePb').val('');
$('#nomePb').val('');
},
dataSource: {
schema: {
parse: function(response) {
var length = response.length;
var dataItem;
var idx = 0;
for (; idx < length; idx++) {
dataItem = response[idx];
dataItem.PBanker = dataItem.cognome + " " + dataItem.nome;
}
return response;
}
},
serverFiltering: true,
transport: {
read: {
url: "http://myFile.json",
data: function(){
return {pb: $('#codPB').val()}
}
}
},
},
});
Do you know any issues about this behavior? Am I acting something wrong?
Try to avoid querying the DOM (with $("#codPB").kendoAutoComplete()) when using angular. You are mixing two different approaches.
In this case, Kendo provides directives to work with angular, see this demo:
HTML
<input kendo-auto-complete ng-model="country"
k-data-source="countryNames" style="width: 100%;" />
JS
angular.module("KendoDemos", [ "kendo.directives" ])
.controller("MyCtrl", function($scope){
$scope.countryNames = [
"Albania",
"Andorra",
//[...]
"Ukraine",
"United Kingdom",
"Vatican City"
];
});
The other solution (less elegant) is to use ng-show instead of ng-if.

Flickity carousel: Items pushed out of viewport with ng-repeat?

Im trying to use metafizzy's flickity framework to display content dynamically, using angulars ng-repeat.
But for some reason the items seem to get pushed out from the flickity-viewport when loaded onto the DOM. Anyone know why that happens and how to avoid it?
The gallery works fine When displaying static content inside it like this;
HTML : STATIC MARKUP EXAMPLE
<div ng-controller="FlickityCtrl">
<div id="main-content" class="gallery js-gallery">
<div class="gallery-cell"> Static Title </div>
<div class="gallery-cell"> Static Title </div>
<div class="gallery-cell"> Static Title </div>
</div>
..its When trying to populate the gallery with the help of angular's ng-repeat directive,that the gallery breaks.
HTML : MARKUP USING NG-REPEAT
<div ng-controller="FlickityCtrl" >
<div id="main-content" class="gallery js-gallery">
<div ng-repeat="chapter in chapters" ng-click="loadSubchapters(chapter.title)">
<h1 class="gallery-cell cell-card-bg">
{{ chapter.title | strip_namespace }}
</h1>
</div>
</div>
<hr>
<button ng-click="loadChapters()" >Load chapters</button>
<hr>
<ul>
<li ng-repeat="chapter in subchapters">
{{ chapter.title | strip_namespace }}
</li>
</ul><br />
<hr >
</div>
JAVASCRIPT
angular.module('FlickityApp', [])
.controller('flickityCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
var updateUI = function(data) {
if (!data || !data.query) { return; }
$timeout(function() {
$scope.chapters = data.query.pages;
console.log(data);
});
};
$scope.loadChapters = function() {
mw.loader.using('mediawiki.api', function() {
(new mw.Api()).get({
action: 'query',
generator: 'categorymembers',
gcmtitle: 'Category:examplepage'
}).done(function(data) {
$timeout(function() {
$scope.chapters = data && data.query ? data.query.pages : {};
});
});
});
};
$scope.loadSubchapters = function(chapterTitle) {
mw.loader.using('mediawiki.api', function() {
(new mw.Api()).get({
action: 'query',
generator: 'categorymembers',
gcmtitle: chapterTitle
}).done(function(data) {
$timeout(function() {
$scope.subchapters = data && data.query ? data.query.pages : {};
});
});
});
};
}])
.filter('strip_namespace', ['$sce', function($sce){
return function(text) {
text = text.split(":");
return text.length > 1 ? text[1] : text[0];
};
}]);
.directive('flickity', [function() {
return {
restrict: 'E',
templateUrl: 'templates/view.html',
replace: true,
scope: { chapters: '=' },
link: function(scope, elem, attrs, ctrl) {
scope.$watch('chapters', function() {
elem.flickity({
// settings
});
});
}
};
}]);
angular.element(document).ready(function() {
angular.bootstrap(document, ['FlickityApp']);
var flkty = new Flickity('.gallery');
});
Link to flickity api : http://flickity.metafizzy.co/api.htm

custom currency filter to the input field in angularjs

How to formatting the value in to indian currency type using angularjs.
for example, 454565 to 4,54,565.00
I have input field like this:
<input type="text" ng-model="item.cost />
function FormatMyNumber(yourNumber) {
// Limit to two decimal places
yourNumber = parseFloat(yourNumber).toFixed(2);
//Seperates the components of the number
var n = yourNumber.toString().split(".");
//Comma-fies the first part
n[0] = n[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
//Combines the two sections
return n.join(".");
}
FormatMyNumber(454565); //yields 454,565.00
You can create directive for it as follows
HTML
<div ng-app="myApp">
<div ng-controller="myCtrl">
{{amount}}
<input format-to-currency amount="amount">
</div>
</div>
JS
angular.module('myApp', [])
.controller('myCtrl', function($scope) {
$scope.ampunt = 2;
})
.directive('formatToCurrency', function($filter) {
return {
scope: {
amount: '='
},
link: function(scope, el, attrs) {
el.val($filter('currency')(scope.amount));
el.bind('focus', function() {
el.val(scope.amount);
});
el.bind('input', function() {
scope.amount = el.val();
scope.$apply();
});
el.bind('blur', function() {
el.val($filter('currency')(scope.amount));
});
}
}
});
Link http://jsfiddle.net/moL8ztrw/6/

Angular ng-repeat issue

I've this controller:
app.controller('HomeController', function($scope) {
$scope.buttonList = [
{
href: "http://ciao.html",
cssClass: "",
iconBeforeCssClass: "",
labelCssClass: "",
labelText: "ciao",
iconAfterCssClass: "",
},
{
href: "ciao2.html",
cssClass: "",
iconBeforeCssClass: "",
labelCssClass: "",
labelText: "ciao2",
iconAfterCssClass: "",
}
];
});
This directive:
app.directive('widgetButtonList', function() {
var directive = {};
directive.restrict = 'E';
directive.replace = false;
directive.templateUrl = 'modules/directives/widget-button-list.html';
directive.scope = {
additionalCssClass: "#",
buttons : "#",
};
return directive; });
The template is the follow:
<div class="ap-block ap-button-list-block {{additionalCssClass}}">
<ul>
<li ng-repeat="btn in buttons track by $index">
<a href="{{btn.href}}" class="{{btn.cssClass}}">
<i class="ap-button-list-before-icon {{btn.iconBeforeCssClass}}" ></i>
<span class="ap-button-list-label {{btn.labelCssClass}}">{{btn.labelText}}</span>
<i class="ap-button-list-after-icon {{btn.iconAfterCssClass}}" ></i>
</a>
</li>
</ul>
And the view is like this:
<div ng-controller="HomeController">
<widget-button-list buttons="{{buttonList}}"></widget-button-list>
But otherwise to render two times the template button as i expected, it print 250 time the widget's template without binding nothing. Can someone help me??
You'll want to pass the buttonsList using a different isolate scope attribute instead of using text-binding. The # symbol on the directive definition object indicates you'll be passing in a string, where you're actually passing in an array of objects. Try this:
directive.scope = {
additionalCssClass: "#",
buttons : "=" //instead of #
};
<widget-button-list buttons="buttonList"></widget-button-list>
Plunker Demonstration
And just for the sake of completeness, you could pass in the buttonsList as a string, but you'll have to be aware that in the directive you'll be recieving a JSON string. Then you'll need to parse it inside the directive:
directive.scope = {
additionalCssClass: "#",
buttons: "#"
};
directive.controller = function($scope) {
$scope.btns = JSON.parse($scope.buttons);
}
I don't suggest this second method, but here's the Plunker Demonstration of that as well.

Resources