I need to call a js function when an ng-repeat template is created:
<div ng-repeat="item in items">
<input id="ip{{item.id}}">
<script>$(function () { $('#ip{{item.id}}').kendoDatePicker(); });</script>
</div>
The id is replaced as expected, but angular doesn't seem to work inside script tags.
That is correct, Angular will not evaluate expressions in script tags. You will need to use a directive that will initialize the Kendo plugin for each element.
The good news is Kendo already has a module for integrating with Angular, so you might as well just use that. Here is a plunk I put together showing it in a repeater.
<div ng-repeat="item in items">
<label for="{{item.id}}">{{item.id}}</label>
<div>
<input kendo-date-picker ng-model="item.value" />
</div>
</div>
Controller:
angular.module("demo", ['kendo.directives'])
.controller('DemoCtrl', ['$scope',
function($scope) {
$scope.items = [{
id: 'item1',
value: null
}, {
id: 'item2',
value: null
}, {
id: 'item3',
value: null
}, {
id: 'item4',
value: null
}];
}
]);
Related
I have an array and I want to take specific element from it using directive (for example array[0]), but I don't understand how to achieve it. I realize that this is the basics of angularjs but I can't find anywhere a solution. Please help :)
Here's the array
$scope.array = [
{
text: '1',
},
{
text: '2',
},
{
text: '3',
}]
And I use that construction in a view
<div ng-repeat="element in array">
<content></content>
</div>
And this is what contains that directive
<p>{{array.text}}</p>
In html :
In content directive you will have to add
bindToController: {data: "="}
You could set the same var in your directive instead of data
<div ng-repeat="element in array">
<content></content>
</div>
directive:
<p>{{element.text}}</p>
If the directive is about customer data you should use {{ customer.text }}, if that is the case you can continue using the same scope like this ...
<div ng-repeat="customer in array">
<content></content>
</div>
directive:
<p>{{customer.text}}</p>
I have the following in my controller:
var myApp = angular.module("myApp", []);
myApp.controller("TestCtrl", ['$scope', function($scope) {
$scope.rows = [
'Facebook',
'Twitter',
'Pinterest',
'Instagram',
'Tumblr',
'Google'
];
}]);
and I'm trying to show the content like this
<div class="container">
<div ng-app="myApp">
<div ng-controller="TestCtrl">
<label ng-repeat="row in rows">
<input type="checkbox" ng-checked="row.selected" ng-model="row.selected" />{{row}}</label>
</div>
</div>
right now the items show, but I can't check the checkboxes,
check this Plunker
In order to have your checkbox checkable, you need to pass a valid ng-model there. In your case, row.selected is invalid since every row is a string and not object.
You can have your $scope.rows array like this instead:
$scope.rows = [{
name: 'Facebook',
selected: false
}, {
name: 'Twitter',
selected: false
}, {
name: 'Pinterest',
selected: false
}, {
name: 'Instagram',
selected: false
}, {
name: 'Tumblr',
selected: false
}];
Here's a forked plunker which has checkboxes checkable
I am using AngularJS UI Bootstrap's accordion. I am using ng-repeat with filter inside the accordion. Now the problem is that I cannot access the filtered variable outside <accordion>. If I ditch the accordion and use simple HTML it works fine.
<div ng-app="myApp">
<div ng-controller="AccordionCtrl">
<div>outside accordion{{filteredCampaigns}}</div>
<input type="text" ng-model="q" placeholder="filter" />
<accordion class="accordion" close-others="true">
<div>inside accordion{{filteredCampaigns}}</div>
<accordion-group ng-repeat="campaign in filteredCampaigns=(campaigns | filter:q)">
<accordion-heading>
<h3>{{campaign.title}}</h3>
</accordion-heading>
<p>{{campaign.content}}</p>
</accordion-group>
</accordion>
</div>
</div>
<script>
var app = angular.module('myApp', ['ui.bootstrap']);
app.controller('AccordionCtrl', ['$scope',
function ($scope) {
$scope.campaigns = [{
title: "Test1",
content: "file1.html"
}, {
title: "Test2",
content: "file2.html"
}, {
title: "Test3",
content: "file3.html"
}];
}]);
</script>
I have also created the fiddle here
This is becuase the sub-directives comes with angular-ui have child scopes that does not reflect this new filteredCampaigns variable to the controller's scope.
1st option - Hack it,
1) define an object to contain the filteredCampaigns dynamic variable
$scope.context = {};
2) change your accordion-group to:
<accordion-group ng-repeat="campaign in context.filteredCampaigns=(campaigns | filter:q)">
http://jsfiddle.net/Lryuvm9m/1/
<script>
var app = angular.module('myApp', ['ui.bootstrap']);
app.controller('AccordionCtrl', ['$scope',
function ($scope) {
$scope.context = {};
$scope.campaigns = [{
title: "Test1",
content: "file1.html"
}, {
title: "Test2",
content: "file2.html"
}, {
title: "Test3",
content: "file3.html"
}];
}]);
</script>
<div ng-app="myApp">
<div ng-controller="AccordionCtrl">
<div>outside accordion {{context.filteredCampaigns}} </div>
<input type="text" ng-model="q" placeholder="filter" />
<accordion class="accordion" close-others="true">
<div>inside accordion{{context.filteredCampaigns}}</div>
<accordion-group ng-repeat="campaign in context.filteredCampaigns=(campaigns | filter:q)">
<accordion-heading>
<h3>{{campaign.title}}</h3>
</accordion-heading>
<p>{{campaign.content}}</p>
</accordion-group>
</accordion>
</div>
</div>
2nd option - use Controller as,
i would recommend using Controller as since it will give you more controll of what's defined on the controller's scope and what's not
http://jsfiddle.net/gntt6h5b/
<script>
var app = angular.module('myApp', ['ui.bootstrap']);
app.controller('AccordionCtrl', ['$scope',
function () {
var vm = this;
vm.campaigns = [{
title: "Test1",
content: "file1.html"
}, {
title: "Test2",
content: "file2.html"
}, {
title: "Test3",
content: "file3.html"
}];
}]);
</script>
<div ng-app="myApp">
<div ng-controller="AccordionCtrl as vm">
<div>outside accordion {{vm.filteredCampaigns}} </div>
<input type="text" ng-model="q" placeholder="filter" />
<accordion class="accordion" close-others="true">
<div>inside accordion{{vm.filteredCampaigns}}</div>
<accordion-group ng-repeat="campaign in vm.filteredCampaigns=(vm.campaigns | filter:q)">
<accordion-heading>
<h3>{{campaign.title}}</h3>
</accordion-heading>
<p>{{campaign.content}}</p>
</accordion-group>
</accordion>
</div>
</div>
<accordion> creates an isolated scope and the filteredCampaigns are only available in that scope, not in the parent scope. To add it to the parent scope, you use $parent:
ng-repeat="campaign in $parent.filteredCampaigns=(campaigns | filter:q)">
Another solution would be creating an creating an object an object in the parent scope with a parameter for the filteredCampaings:
// AccordionCtrl
$scope.filteredValues = {
filteredCampaings: []
};
ng-repeat="campaign in filteredValues.filteredCampaigns=(campaigns | filter:q)"
Since you're using it outside of the ng-repeat, you can't see that variable as ng-repeat creates its own scope.
You can use the controller and use the filter manually to retrieve the filtered objects:
$scope.getFilteredCampaings = function () {
$scope.filteredCampaigns = $filter('filter')($scope.campaigns, $scope.q);
return $scope.filteredCampaigns;
}
Fiddle
I have a variable set to true in ng-click but the div underneath is not displaying. I've followed this post but it looks like it doesnt work in maybe ng-repeat? Here's the plunker: http://plnkr.co/edit/90G1KAx9Fmf2SgRs5gYK?p=preview
angular.module('myAppApp', [])
.controller('MainCtrl', function ($scope) {
$scope.notes = [{
id: 1,
label: 'First Note',
done: false,
someRandom: 31431
}, {
id: 2,
label: 'Second Note',
done: false
}, {
id: 3,
label: 'Finished Third Note',
done: true
}];
$scope.reach= function (id) {
//the assignment below works
//$scope.flag = true;
alert("hello there");
};
});
<div ng-app="myAppApp">
<div ng-controller="MainCtrl">
<div ng-repeat="note in notes">
{{note.id}} - {{note.label}} -
click me
</div>
<div class="row" id="" ng-show="flag">I'm Here</div>
</div>
</div>
It should be ng-click="$parent.flag = true;reach(111);"
click me
Outside ng-repeat
You question is unclear, you could use ng-repeat inside ng-repeat, by maintaining variable in ng-repeat parent scope. and access parent scope using $parent. annotation inside ng-repeat
<div ng-repeat="note in notes">
{{note.id}} - {{note.label}} -
click me
<div class="row" id="" ng-show="$parent.selected == note.id">I'm Here</div>
</div>
</div>
Inside ng-repeat
I would advise you to use ng-init
<div ng-repeat="note in notes" ng-init="parent=$parent">
and after that
click me
Please see demo below
angular.module('myAppApp', [])
.controller('MainCtrl', function($scope) {
$scope.notes = [{
id: 1,
label: 'First Note',
done: false,
someRandom: 31431
}, {
id: 2,
label: 'Second Note',
done: false
}, {
id: 3,
label: 'Finished Third Note',
done: true
}];
$scope.reach = function(id) {
//$scope.flag = true;
alert("hello there");
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<div ng-app="myAppApp">
<div ng-controller="MainCtrl">
<div ng-repeat="note in notes" ng-init="parent=$parent">
{{note.id}} - {{note.label}} -
click me
</div>
<div class="row" id="" ng-show="flag">I'm Here</div>
</div>
</div>
</body>
I want to render a form, based on a dynamic field configuration:
$scope.fields = [
{ title: 'Label 1', type: 'text', value: 'value1'},
{ title: 'Label 2', type: 'textarea', value: 'value2'}
];
This should output something that behaves like:
<div>
<label>{{field.title}}<br />
<input type="text" ng-model="field.value"/>
</label>
</div>
<div>
<label>{{field.title}}<br />
<textarea ng-model="field.value" rows="5" cols="50"></textarea>
</label>
</div>
The simple implementation would be to use if statements to render the templates for each field type. However, as Angular doesn't support if statements, I'm lead to the direction of directives. My problem is understanding how the data binding works. The documentation for directives is a bit dense and theoretical.
I've mocked up a bare bones example of what I try to do here: http://jsfiddle.net/gunnarlium/aj8G3/4/
The problem is that the form fields aren't bound to the model, so the $scope.fields in submit() isn't updated. I suspect the content of my directive function is quite wrong ... :)
Going forward, I need to also support other field types, like radio buttons, check boxes, selects, etc.
The first problem you are running into regardless of the directive you are trying to create is using ng-repeat within a form with form elements. It can be tricky do to how ng-repeat creates a new scope.
This directive creates new scope.
I recommend also instead of using element.html that you use ngSwitch instead in a partial template.
<div class="form-row" data-ng-switch on="field.type">
<div data-ng-switch-when="text">
{{ field.title }}: <input type="text" data-ng-model="field.value" />
</div>
<div data-ng-switch-when="textarea">
{{ field.title }}: <textarea data-ng-model="field.value"></textarea>
</div>
</div>
This still leaves you with the problem of modifying form elements in child scope due to ng-repeat and for that I suggest using the ngChange method on each element to set the value when an item has changed. This is one of the few items that I don't think AngularJS handles very well at this time.
You might consider Metawidget for this. It uses JSON schema, but is otherwise very close to your use case. Complete sample:
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/metawidget-core.min.js" type="text/javascript"></script>
<script src="http://metawidget.org/js/3.5/metawidget-angular.min.js" type="text/javascript"></script>
<script type="text/javascript">
angular.module( 'myApp', [ 'metawidget' ] )
.controller( 'myController', function( $scope ) {
$scope.metawidgetConfig = {
inspector: function() {
return {
properties: {
label1: {
type: 'string'
},
label2: {
type: 'string',
large: true
}
}
}
}
}
$scope.saveTo = {
label1: 'value1',
label2: 'value2'
}
$scope.save = function() {
console.log( $scope.saveTo );
}
} );
</script>
</head>
<body ng-controller="myController">
<metawidget ng-model="saveTo" config="metawidgetConfig">
</metawidget>
<button ng-click="save()">Save</button>
</body>
</html>
The type attribute can be changed when the element is out of DOM, so why not a small directive which removes it from DOM, changes it type and then add back to the same place?
The $watch is optional, as the objective can be change it dynamically once and not keep changing it.
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.rangeType = 'range';
$scope.newType = 'date'
});
app.directive('dynamicInput', function(){
return {
restrict: "A",
link: linkFunction
};
function linkFunction($scope, $element, $attrs){
if($attrs.watch){
$scope.$watch(function(){ return $attrs.dynamicInput; }, function(newValue){
changeType(newValue);
})
}
else
changeType($attrs.dynamicInput);
function changeType(type){
var prev = $element[0].previousSibling;
var parent = $element.parent();
$element.remove().attr('type', type);
if(prev)
angular.element(prev).after($element);
else
parent.append($element);
}
}
});
span {
font-size: .7em;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MainCtrl">
<h2>Watching Type Change</h2>
Enter Type: <input ng-model="newType" /><br/>
Using Type (with siblings): <span>Before</span><input dynamic-input="{{newType}}" watch="true" /><span>After</span><Br>
Using Type (without siblings): <div><input dynamic-input="{{newType}}" watch="true" /></div>
<br/><br/><br/>
<h2>Without Watch</h3>
Checkbox: <input dynamic-input="checkbox" /><br />
Password: <input dynamic-input="{{ 'password' }}" value="password"/><br />
Radio: <input dynamic-input="radio" /><br/>
Range: <input dynamic-input="{{ rangeType }}" />
</div>
Tested in latest Chrome and IE11.