Pass json value as ng-model value in angular 1.2 - javascript

I'm trying to bind 2 separate elements so that one can trigger the other. The first step in this, is adding an identifying variable to my component template.
Here's the bullet.html template:
<div class="button bullet" ng-model="component.bullet.show_on_click" ng-click="showElementByUniqueName( component.bullet.show_on_click )"><p>{{component.bullet.text}}</p></div>
I'd like to know what is the correct syntax to set ng-model as the VALUE in component.bullet.show_on_click. At the moment, in the final html, ng-model turns out just as shown in the template. I have tried single speech marks and single AND double curly braces; All throw errors.
Any help, much appreciated!
EDIT
On request, here is some more detail:
The eng-bullet attribute fires up the engBullet directive:
app.directive('engBullet', function() {
return {
restrict: 'A',
replace: true,
templateUrl: 'components/bullet.html',
link: function(scope, element, attrs) {
// following function referenced in bullet.html
scope.showElementByUniqueName = function (showOnClick) {
// remove 'replaces' element
$('#'+$('#'+showOnClick).attr('data-replaces')).addClass('hidden');
// hide all popups (in case another popup is currently visible)
$('.popup').addClass("hidden");
// show selected popup
$('#'+showOnClick).removeClass("hidden");
}
}
};
});
The eng-popup attribute fires up the engPopup directive:
app.directive('engPopup', function() {
return {
restrict: 'A',
replace: true,
templateUrl: 'components/popup.html',
link: function(scope, element, attrs) {
scope.show = true;
scope.complete = false;
// watch for this popup being made visible and check if
scope.$watch(function() { return element.is(':visible') }, function() {
scope.$parent.componentCompleted(attrs.id);
});
}
};
});
..which loads in the components/popup.html template:
<div class="hidden popup {{component.popup.type}}" id="{{component.popup.name}}" data-replaces="{{component.popup.replaces}}" eng-completable ng-show="component.popup.name">
<div ng-if="component.popup.type=='overlay'">
<div class="float-right button close-button">X</div>
</div>
<p class="heading">{{component.popup.heading}}</p>
<div class="popup-content">
<div ng-if="0" ng-repeat-start="(innerIndex, component) in component.popup.popup_components"></div>
<div ng-if="0" ng-repeat-start="(type, object) in component"></div>
<div ng-attr-id="{{'p' + pageId + '-s' + skey + '-c' + ckey + '-component-' + index + '-innerComponent-' + innerIndex}}" ng-switch="type">
<div ng-switch-when="image" eng-image></div>
<div ng-switch-when="paragraph" eng-paragraph></div>
</div>
<div ng-if="0" ng-repeat-end></div>
<div ng-if="0" ng-repeat-end></div>
</div>
</div>
I'm not sure this is really relevant to the question though, which is how do I get the VALUE in component.bullet.show_on_click to present in the final html as the value of ng-model in the bullet html template, eg:
ng-model="unique_name_here"
?
Thanks.

Related

Reuse directive multiplie times with dynamic attributes in another directive's template

What i want to do is to be able to use a directive with different attributes in the same ng-app. The main goal is to run different code when the directive's input (ng-model) changes.
This is what i have now:
app.directive('customInput',
function ($compile) {
var customInputDefinitionObject = {
restrict: 'E',
replace: true,
scope: {
ident: '#'
},
template: '<input type="text" >',
controller: 'customInputController',
compile: function (tElement, tAttrs) {
$('input').removeAttr('ident')
.attr('ng-model', tAttrs.ident)
.attr('ng-change', tAttrs.ident + 'Change()');
var elemLinkFn = $compile(tElement);
return function (scope, element) {
elemLinkFn(scope, function (clone) {
element.replaceWith(clone);
})
}
}
}
return customInputDefinitionObject;
});
It works well in html e.g.:
<custom-input ident="var1"></custom-input>
<custom-input ident="var2"></custom-input>
i'm going to get to input with different ng-model and ng-change function, the controller uses dynamic names to get the $scope variables( $scope.var1Change).
The problem start when i want to use this directive inside another template.
app.directive('customInputGroup', function ($compile) {
var customInputGroupDefinitonObject = {
restrict: 'E',
replace: true,
scope: {
rident: '#',
},
template:''+
'<div>'+
'<custom-input id="first"></custom-input>'+
'<custom-input id="second"></custom-input>'+
'</div>',
controller: 'customInputGroupController',
compile: function (elem, attrs) {
$('#first', elem).removeAttr('id').attr('ident', attrs.rident + 'Start');
$('#second', elem).removeAttr('id').attr('ident', attrs.rident + 'End');
var rangeLinkFn = $compile(elem);
return function (scope, element) {
rangeLinkFn(scope, function (clone) {
element.replaceWith(clone);
})
}
}
}
return customInputGroupDefinitonObject;
});
In this case if i'm going to use it inside the HTML e.g.:
<custom-input-group rident='sg'></custom-input-group>
what i get rendered:
<div>
<input ng-model="sgEnd" ng-change="sgEndChange()">
<input ng-model="sgEnd" ng-change="sgEndChange()">
<input ng-model="sgEnd" ng-change="sgEndChange()">
</div>
For the 3rd rendered input the ng-change does not working.
If set terminal:ture in the inputGroup directive i get only to "input" rendered but both of them has the same ng-model and ng-change.
So how can i make it to render something like this:
<div>
<input ng-model="sgStart" ng-change="sgStartChange()">
<input ng-model="sgEnd" ng-change="sgEndChange()">
</div>
And if u know how would u be so nice to let me know only the "how" but the "why" aswell.
Thank you in advance.

Why is my directive updating as a result of changes in another instance of the same directive?

I created a simple directive wrapper around the HTML file input to make angular binding work. Here's my directive:
angular.module('myApp').directive('inputFile', InputFileDirective);
function InputFileDirective() {
var bindings = {
selectLabel: '#',
};
return {
restrict: 'E',
require: ['inputFile', 'ngModel'],
scope: true,
controllerAs: 'inputFileCtrl',
bindToController: bindings,
controller: function () {
},
template: `<input class="ng-hide" id="input-file-id" type="file" />
<label for="input-file-id" class="md-button md-raised md-primary">{{ inputFileCtrl.getButtonLabel() }}</label>`,
link: link
};
function link(scope, element, attrs, controllers) {
if (angular.isDefined(attrs.multiple)) {
element.find('input').attr('multiple', 'multiple');
}
var inputFileCtrl = controllers[0];
var ngModelCtrl = controllers[1];
inputFileCtrl.getButtonLabel = function () {
if (ngModelCtrl.$viewValue == undefined || ngModelCtrl.$viewValue.length == 0) {
return inputFileCtrl.selectLabel;
}
else {
return ngModelCtrl.$viewValue.length + (ngModelCtrl.$viewValue.length == 1 ? " file" : " files") + " selected";
}
};
element.on('change', function (evt) {
ngModelCtrl.$setViewValue(element.find('input')[0].files);
ngModelCtrl.$render();
});
}
};
And here's the HTML
<body ng-app="myApp" ng-controller="MyController as ctrl">
<form name="ctrl.myForm">
<input-file select-label="Select Attachment" ng-model="ctrl.attachment1"></input-file>
<input-file select-label="Select Attachment" ng-model="ctrl.attachment2"></input-file>
</form>
</body>
It's pretty simple and it works - if only one is on the page. As soon as I add a second one, I notice that only the first one ever updates. If I select a file with the second one, the label updates on the first one. My suspicions are that the require ['inputFile'] is pulling in the controller for the first directive instance into the link function or something (which shouldn't happen). Even now as I type this, that doesn't really make sense to me. So what's going on here and how do I fix it?
Here's a codepen for you guys to play with and try to figure it out: http://codepen.io/astynax777/pen/PzzBRv
Your problem is not with your angular... is with you html.
You are assigning the same id twice.
Change your template to this:
template: `<label class="md-button md-raised md-primary">{{ inputFileCtrl.getButtonLabel() }}<input class="ng-hide" type="file" /></label>`

Directive with same template but with dynamic content

HTML :
<div custDirective id="managerNames"></div>
<div custDirective id="empNames"></div>
Template.html
<div ng-repeat="name in names">
<ol><li>{{name}}</li></ol>
</div>
Directive link function :
if(attr.id === "name"){
scope.names = ["A","B","C","D"];
}else{
scope.names = ["E","F","G","H"];
}
I want to get the dynamic list based on the id attribute.i.e, If id is managerNames then my ng-repeat should repeat a,b,c,d else it should repeat e,f,g,h.
How to achieve this? I am using angular.js 1.2 version.
you can send an attribute to your link where it will check on the value you send to it and work accordingly to it
Here is an example :
//Directive
angular.module('yourModule').directive('directiveName',
function($parse) {
return {
restrict: 'E',
templateUrl: "your/template.html",
scope: {
check: '#',
},
link: function(scope, element, attrs) {
if(scope.check == "whatever"){
}
}
})
//HTML
<directive-name check="whatever"></directive-name>

Use link function in directives to append different HTML elements

Fiddle
I have two buttons. When pressed it displays a modal, with som text. But I also want to add some html dynamically depending on which button is pressed.
I have tried both $observe and $watch methods, but I'm having problems making it work.
here is my code.
angular.module('TM', [])
.controller('protocolCtrl', function(){
this.text = 'Now looking at the protocol part';
this.modalId = 'protocolModal';
})
.controller('categoryCtrl', function(){
this.text = 'Now looking at the category part';
this.modalId = "categoryModal";
})
.directive('modalDirective', function(){
return {
restrict: 'E',
scope: {
ctrl: '=',
modalId: '#',
},
template: ['<div id="{{modalId}}" class="modal fade" role="dialog">',
'<div class="modal-dialog">',
'<div class="modal-content">',
'<div class="modal-header">',
'<h4 class="modal-title">Modal Header</h4>',
'</div>',
'<div class="modal-body">',
'<p> {{ ctrl.text }} </p>',
'</div>',
'<div class="modal-footer">',
'<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>',
'</div>',
'</div>',
'</div>',
'</div>'].join(''),
link: function(scope, element, attrs) {
element.$observe('modalId', function(){
var modal = element.find('#{{modalId}}');
if(modal == 'protocolModal'){
element.find('#{{modalId}}').append('<div>this is a protocol test...</div>');
} else {
element.find('#{{modalId}}').append('<div>this is a category test...</div>');
}
});
}
}
});
I don't think there is element.$observe - there is attrs.$observe and scope.$watch. You already have modelId on the scope, so let's use that.
Also, instead of the wonky .find by id, inject an element as a placeholder for the template and replaceWith it accordingly:
template: '<div id="{{modalId}}">\
...\
<div class="modal-body">\
<template-placeholder></template-placeholder>\
</div>\
</div>",
link: function(scope, element){
// ...
var unwatch = scope.$watch("modalId", function(val){
var placeholder = element.find('template-placeholder');
if(val == 'protocolModal'){
placeholder.replaceWith('<div>this is a protocol test...</div>');
} else {
placeholder.replaceWith('<div>this is a category test...</div>');
}
unwatch(); // seems like you don't really need to set it again
}
}
See i updated your Fiddle
Use attr in link function. because you already given attribute to
your html i.e: modal-id="{{pctrl.modalId}}
<modal-directive ctrl="pctrl" modal-id="{{pctrl.modalId}}"></modal-directive>
if(attrs.modalId == 'protocolModal'){
element.find('#{{modalId}}').append('<div>this is a protocol test...</div>');
} else {
element.find('#{{modalId}}').append('<div>this is a category test...</div>');
}
Edit :
use $timeout
$timeout(function () {
if (attrs.modalId == 'protocolModal') {
element.find('#' + attrs.modalId).append('<div>this is a protocol test...</div>');
} else {
element.find('#' + attrs.modalId).append('<div>this is a category test...</div>');
}
}, 1000)
Now why $timeout because you are applying template and and at same
time your link function append your div so it will not apply your div
.So first apply template and then in template append your div
And if you want to show that div in popup content the use this selector.
see this example: https://jsfiddle.net/kevalbhatt18/o76hxj69/6/
element.find('#'+attrs.modalId +' .modal-body').append('<div>this is a protocol test...</div>');
If your two DOM structure diverses, you can consider using two different templates depending on some parameter value.
templateUrl can be specified as a function, such as:
angular.module('Joy', [])
.controller('ProfileCtrl', ['$scope', function ($scope) {
$scope.user = {
name: 'Elit'
};
}])
.directive('profile', [function () {
return {
restrict: 'A',
templateUrl: function (elem, attrs) {
return 'style-' + attrs.color + '.html';
}
};
}]);
And use the directive as:
<div ng-app="Joy" id="play-ground" ng-controller="ProfileCtrl">
<div profile color="red"></div>
<div profile color="green"></div>
</div>
In this case, if the color is red, the directive will load template from style-red.html. Otherwise from style-green.html.
In your case, you might maintain a flag in the outside controller. Clicking either button will change this flag value and pass in to the directive. The directive will load different templates accordingly.

AngularJs controller add all html elements from template

I want to add all my elements from my template to my $scope.
I want them to be accessible like c# or java elements in the code.
for example
if i have this HTML template
<div ch-options-div id="chOptions" ng-controller="chOptionsCtrl">
<span>Options</span>
<div id="chOptionsWrapper">
<div id="div1">
</div>
<div id="div2"></div>
<div id="div3"></div>
</div>
</div>
And here is a possible controller:
var chOptions = angular.module('chOptions',[]);
chOptions.controller('chOptionsCtrl', function ($scope,$document,$element)
{
//select all elements by id and add them to scope
$scope.chOptionsWrapper = document.getElementById('chOptionsWrapper');
//or with jquery
$scope.div1 = $('#div1')
}
Is there a best case to do this or is there a good way to add all my HTML elements to the scope ? I want clean "object oriented" javascript code.
You can use a directive to achieve this.
.directive('box', function () {
return {
scope: {
rgb: '='
},
link: function (scope, elem, attrs) {
scope.$watch('rgb', function () {
angular.element(elem).css('background-color', 'rgb(' + scope.rgb + ')');
});
}
}
}
Here is an example of you to use the directive: http://jsfiddle.net/skriblez/dqfwvyso/4/

Categories

Resources