I have 4 templates being shown based upon var.type. I have 2/4 showing properly, but for some reasons 2 of them are not rendering anything. In the HTML I see the switch being properly activated, but the directive isn't being placed inside as expected.
angular.module('lodgicalWebApp');
angular.module('lodgicalWebApp')
.directive('lodReportVariableCgflookup', function () {
return {
template: '{{var.name}}<label for="repeatSelect"> {{var.name}} </label> \
<select name="repeatSelect" ng-model="Vars[var.name]" id="repeatSelect" ng-model="data.repeatSelect"> \
<option ng-repeat="option in var.possibleVals" value="{{option.id}}">{{option.name}}</option> \
</select>',
restrict: 'EA'
};
});
angular.module('lodgicalWebApp')
.directive('lodReportVariableBoolean', function () {
return {
template: '{{var.name}}<input ng-model="Vars[var.name]" type="checkbox" ng-true="{{var.value}}">',
restrict: 'EA',
};
});
angular.module('lodgicalWebApp')
.controller('ReportsCtrl', function ($scope, $routeParams, LodgicalReportService, Report) {
$scope.selectedReport.variables = [
{name: "Start Date",possibleVals:[],type: "Date", value: "2016-01-18"},
{name: "Operator",possibleVals: [{id:1,name:"test"},{id:2,name:"thanksStackOverflow"}], type: "CfgLookup"},
{name: "Include Security Deposits", type: "Boolean", value: "False"}
]
});
<div ng-repeat="var in selectedReport.variables">
<div ng-switch="var.type">
<!-- CfgLookup not rendering -->
<div ng-switch-when="CfgLookup" data-lod-report-variable-cfglookup ></div>
<div ng-switch-when="Boolean" data-lod-report-variable-boolean></div>
<div ng-switch-when="Date" data-lod-report-variable-date ></div>
<div ng-switch-when="CfgLookup-Multi" data-lod-report-variable-cfglookup></div>
</div>
</div>
This isn't a functioning example, but it should illustrate enough to hopefully shine some light on this major frustration.
Thanks in advance.
You have a typo that would surely mess it up:
"data-lod-report-variable-cfglookup" is what you wrote in the HTML code as the directive name, while the directive name in your JS code is "lodReportVariableCgflookup". (cfglookup vs cgflookup)
EDIT: In addition, I noticed that you used the same directive "lodReportVariableCgflookup" on both the directives that you say are not working.
It's possible you have another issue as well, but I'd start with that one :)
Related
I have a drop down component in angularjs which when used single time works fine and the values are selected but if I use the same component multiple times in ng-repeat the drop downs are rendered but the values are not being selected. I am using the following code:
JS file:
angular.module('mainApp').component('inputSelectComponent', {
templateUrl : 'sys/templates/input-select.template.html',
bindings : {
ngModel : '='
},
controller: ['$scope', '$element', '$http', 'translate', 'apiServer', 'session', 'EVENTS', function compCategoriesDropdownController($scope, $element, $http, translate, apiServer, session, EVENTS) {
var _select = $element.find('select');
$scope.options = JSON.parse($element.attr('options'));
setTimeout(function(){
$element.find('select').selectize({});
}, 0);
$scope.$watch('$ctrl.ngModel', function(e){
var selectize = _select[0].selectize;
if (typeof(selectize) !== 'undefined') {
setTimeout(function(){
selectize.setValue(e);
}, 0);
}
});
$scope.$watch('$element.attr', function(e){
$scope.label = $element.attr('label');
if ($element.attr('disabled') === 'disabled'){
_select.attr('disabled', 'disabled');
}
});
$element.find('select').on('change', function(e){
$scope.$ctrl.ngModel = e.target.value;
});
}]
});
Template file:
<label class="col-form-label">{{label}}</label>
<select class="cat-drop{{(error!=null)? ' not-validated' :''}}">
<option ng-repeat="(key, value) in options" value="{{key}}">
{{value}}
</option>
</select>
This is how I am calling it:
<div ng-repeat="relatedproduct in relatedproductsData">
<span class="serial-number">{{ $index + 1 }}.</span>
<div class="form-group row">
<input-select-component ng-model="relatedproduct.item_type" class="input-component col-sm-2" label="{{t('related_products_item_type')}}" options='{"2": "2 - For Product", "3": "3 - For Category"}'></input-select-component>
</div>
</div>
Any help is appreciated!
I used a directive instead of an component.
The documentations says:
Components only control their own View and Data: Components should never modify any data or DOM that is out of their own scope. ..
Using a directive allows you to usa ng-model="ngModel" on the select component in the directive and change the value directly.
angular.module('mainApp').directive('inputSelectComponent', function () {
return {
template: `<label class="col-form-label">{{label}}</label>
<select class="cat-drop{{(error!=null)? ' not-validated' :''}}" ng-model="ngModel">
<option ng-repeat="(key, value) in options" value="{{key}}">
{{value}}
</option>
</select>`,
scope: {
ngModel: '=',
options: '=',
}
}
});
it does work in the caller:
<div ng-repeat="relatedproduct in [{ item_type : '' }, {item_type : ''}, { item_type: '' }]">
<span class="serial-number">{{ relatedproduct }}.</span>
<div class="form-group row">
<input-select-component ng-model="relatedproduct.item_type"
class="input-component col-sm-2"
label="{{t('related_products_item_type')}}"
options='{"2": "2 - For Product", "3": "3 - For Category"}'></input-select-component>
</div>
</div>
Good luck!
Try using $timeout instead of setTimeout. Maybe because of angularJS digest...
I'm generating a template multiple times in the same page, however a function of this template's controller will work on the whole page. How can make sure it only works within the respective template scope?
In this example, when the user clicks a small div, its content it will travel to another div. How does this work? I select the clicked div with a specific class name using jquery and append it to the div it should travel to. However, as I'm calling this template multiple times, the function will select all classes in the page with that same class name, instead of just the template scope.
How can I make it that the selector will only look into the template's scope?
Here's the template:
<div ng-controller="templateController">
<div class="source">
<div ng-repeat="item in info">
<div class="content" data-value="{{item.ID}}">{{item.name}}</div>
</div>
</div>
<br style="clear:both" />
<div class="receiver"></div>
<div>
</div>
And here's the controller with some jquery functions:
angular
.module("demo")
.controller("templateController", ["$scope", "$timeout", function($scope, $timeout) {
$scope.info = [
{
name: "john",
ID: 1
},
{
name: "Edward",
ID: 0
},
{
name: "Carl",
ID: 2
}
];
$timeout(function () {
$(".source .content").click(function () {
console.log("leaving source");
$(this).appendTo($(".receiver"));
})
});
$timeout(function () {
$(".receiver .content").click(function () {
console.log("leaving receiver");
$(this).appendTo($(".source"));
})
});
I also would like to travel back to its original container (as shown in the second function but seems to not be working), but it only travel in one direction.
Here's a simple plunk with the whole code so you can see it work and see what's wrong
enter link description here
Thank you
I have a form that I want to build at run time via js and use it in a form controller in angularjs.
As you can see in the following example, it is not being thrown as html, and i want it to be binded to the model variable. http://jsfiddle.net/g6m09eb7/
<div>
<form ng-controller="TodoCtrl" ng-submit="blabla()">
<div ng-repeat="field in fields">{{field.input}}</div>
</form>
</div>
function TodoCtrl($scope) {
$scope.model = {
'FirstName': 'Test',
'LastName': 'Test Last'
}
$scope.fields = [{
input: '<input type="text" ng-model="model.FirstName">'
}, {
input: '<input type="text" ng-model="model.LastName">'
}, ];
}
First, I'm going to show you how to make this work as you're trying to accomplish it, for the sake of being informative. This is not the approach you should use to solve your overall problem. This example will get the html in the document, but it won't be compiled with Angular. To do that, you would have to have a different directive, like this (click). This is all kinds of a bad approach.
angular.module('myApp', [])
.controller('TodoCtrl', function($scope) {
$scope.fields = [{
input: '<input type="text" ng-model="model.FirstName">'
}, {
input: '<input type="text" ng-model="model.LastName">'
}, ];
})
// filter to make Angular trust the html
.filter('safeHtml', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml(text);
};
}])
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="myApp" ng-controller="TodoCtrl">
<!-- use ng-bind-html on trusted html to bind it (see the js) -->
<div ng-repeat="field in fields" ng-bind-html="field.input | safeHtml"></div>
</form>
Instead, you can do this naturally. Just use the properties of your object as the criteria for ng-repeat. Simple and clean!
angular.module('myApp', [])
.controller('TodoCtrl', function($scope) {
$scope.model = {
'FirstName': 'Test',
'LastName': 'Test Last'
};
})
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<form ng-app="myApp" ng-controller="TodoCtrl">
<div ng-repeat="(key,value) in model">
<input type="text" ng-model="model[key]"/>
</div>
</form>
Be sure to avoid concerning your controller with DOM manipulation. If you have html snippets in a controller, your approach is probably off track. DOM manipulation should be done entirely with directives.
I might be missing something stupidly as this simple code doesn't work as expected. What is wrong is the $scope.change function in the MainCtrl doesn't work (no alert box popped up).
In a nutshell, the view is (it's in jade, better to view?)
<body ng-app="epfApp">
...
label(ng-repeat="question in questions")
| {{ question.title }}
input(type="{{question.type}}", ng-change="change()")
and in the controller file
angular.module('epfApp')
.controller('MainCtrl', function ($scope, $window) {
$scope.questions = {
'1': {
'title': 'The first question is?',
'type': 'text',
'placeholder': 'first question'
},
'2': {
'title': 'The second question is?',
'type': 'text',
'placeholder': 'second question'
}
};
$scope.change = function() {
$window.alert('text');
};
});
And the route:
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
});
Now what it is doing properly is that it correctly populates the view with the data created (i.e. the questions json). However, What it is not doing properly is the change() function bound to the input textbox doesn't work.
What am I missing here? This obviously is a very basic job.
ng-change requires ng-model as well.
<div ng-controller="MainCtrl">
<label ng-repeat="question in questions">
{{question.title}}
<input type="{{question.type}}" ng-model="question.placeholder" ng-change="change()" />
<br />
</label>
</div>
Check out this JSFiddle.
ng-change not working but it work if you define ng-model="yourValue"... like this
<select id="editSelect" ng-model="Option" ng-change="okChange()" name="Option">
<option ng-repeat="data in Option" value="{{data.Option}}">{{data.Option}}</option>
</select>
<div ng-app ng-controller="myCtrl">
<input type="file" ng-model="image" onchange="angular.element(this).scope().uploadImage()" />
<ul>
<li ng-repeat="item in uploadcollection">
{{item.name}} ({{item.size}})
</li>
</ul>
function myCtrl($scope) {
$scope.uploadImage = function () {
$scope.uploadcollection.push({name: "Income.pdf", size: "10mb"});
$scope.$apply();
}
$scope.uploadcollection = [{name: "Income.pdf", size: "10mb"}, {name: "Expense.pdf", size: "1.5mb"}];
}
I have created a demo here: http://jsfiddle.net/fA968/120/
NOTE: This Example not worked with v1.4.8: https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js
Update
Here is an simple way to do this:
var myApp = angular.module('myApp', []);
myApp.directive('customOnChange', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var onChangeFunc = scope.$eval(attrs.customOnChange);
element.unbind('change').bind('change', function(e) {
onChangeFunc(e);
});
}
};
});
Here is an updated Fiddle
When the expression inside of the ng-change="" is something which errors (like with a spelling error) it will not log the error to the console. You will not know anything is amiss except for the fact that nothing happens.
Make sure to spell things correctly and to prefix the alias you give the "Controller As" syntax, if applicable.
I'd like to define meta data which will dynamically use the correct directive based on a "type" value:
$scope.items = [
{
type: 'directive-one',
value: 'One'
},{
type: 'directive-two',
value: 'Two'
},{
type: 'directive-three',
value: 'Three'
}
];
and then
<li ng-repeat="item in items" {{type}}>
{{value}}
</li>
I've created a jsfiddle here. So far I've had no success
Is this possible? How would I accomplish this?
Here is an alternative way of solving the problem:
Use ngSwitch to map between type and directive.
<li ng-repeat="item in items">
<div ng-switch on="item.type">
<div ng-switch-when="type-one" directive-one>
</div>
<div ng-switch-when="type-two" directive-two>
</div>
<div ng-switch-when="type-three" directive-three>
</div>
</div>
</li>
See jsfiddle
But if you really need to define the directive in the metadata, you can add a directive that will generate the div element with the appropriate directive
angular.module('myApp').directive('dynamicDirective', function($compile) {
return {
restrict: 'A',
link: function (scope, ele) {
//add a child div element that contains the directive specified in the type property
var itemEl = angular.element('<div>').attr(scope.item.type,'');
$compile(itemEl)(scope);
ele.append(itemEl);
}
};
});
See jsfiddle