Custom directive with dynamic field name in ng-repeat - javascript

I am creating reusable custom directive in angularjs where I am looking to pass fieldName for ng-repeate items as attribute. All my scope is isolated
My part of directive codes as below
<div class="list">
<label ng-repeat="item in items" class="item item-text-wrap">
{{item.City}}
</label>
</div>
In above code I am passing fieldName hard code but I want to pass City (i.e. field name) by attribute
of my custom directive
<custom-select items="deptStations" drop-down-field="City"></custom-select>
in above items are passed by http service from controller
.controller('Ctrl', function($scope, $http) {
$http.get("http://www.xxxx.com/_api/lists/getbytitle('XXX')/items?$select=Id,City_Code,City&$filter=Active eq 1&$orderby=City asc", {
headers: {
Accept : "application/json;odata=verbose"
}
}).then(function(resp) {
$scope.deptStations = resp.data.d.results;
}, function (err) {
console.log(err);
});
});
So idea over here is that I want to pass drop-down-field and I want to pass in my directive. Is it possible, if yes then how ?

i think below code will solve your problem
angular.module("module").directive("customSelect", function(){
return{
scope : {
dropDownField : '#',
items : '='
};
};
});
<div class="list">
<label ng-repeat="item in items" class="item item-text-wrap">
{{item[dropDownField]}}
</label>
</div>

Related

How do I dynamically access a property inside an angularjs directive?

I have a directive when given an array it creates check boxes for that list of items using the Name as the label for the checkbox.
Html
<div>
<a style="float:right; margin-bottom: 5px;" ng-click="selectNone()" href="#">Select None</a>
<a style="float:right; margin-bottom: 5px;margin-left: 10px" ng-click="selectAll()" href="#">Select All</a>
<div class="cleared"></div>
<div class="form-input form-list">
<label ng-repeat="item in valuelist | orderBy:'Name'">
<input type="checkbox" checklist-model="model" checklist-value="item" /> {{item.Name}}<br />
</label>
</div>
JS
'use strict';
growllApp.directive('checkboxlist', [function () {
return {
restrict: 'E',
templateUrl: 'scripts/modules/checkboxlist.template.html',
controller: 'checkboxlistController',
scope: {
model: "=",
value: "=",
valuelist: "="
}
}
}]);
growllApp.controller('checkboxlistController', ['$scope', '$routeParams', '$location', '$cookieStore', function ($scope, $routeParams, $location, $cookieStore) {
$scope.selectAll = function () {
$scope.model = angular.copy($scope.valuelist);
};
$scope.selectNone = function () {
$scope.model = [];
};
}]);
Using the directive
<checkboxlist ng-show="applyToProducts" model="coupon.Products" value="Name" valuelist="productsList"></checkboxlist>
All this works fine in most scenarios. However, I have a scenario where the array I'm passing in has objects in it that do not have the property "Name" but instead have the property "Title".
How do I use the attribute I have in the directive called "value" for the part that determines the label.
So in the directive html instead of saying {{item.Name}} how can I specify {{item.Title}} by passing in that the property name is title in certain cases?
You can change the 'value' attribute of your directive to '#' (it means the value will be sent as a string to your directive. You can read more in this article )
scope: {
model: "=",
value: "#",
valuelist: "="
}
and to get the object's property, you can do:
{{item[value]}}
In addition to the answer suggesting a ternary operator you could simplify that to be something like
{{ item.Name || item.Title }}
and you could have as many alternatives as you need.
However, a more robust approach I think would be to do like someone else suggested and say
scope : {
...
key:'#'
...
}
where key is the name of the property and the access it like
{{ item[key] }}
You could try using a ternary operator:
{{ item.Name ? item.Name : item.Title }}
You would probably need to use a custom comparator for the orderBy then.

AngularJS ng-repeat an object

I'm getting an object as the scope. The object looks like this:
And my controller looks like this:
module.controller('ActiveController', ['$scope','$http',
function($scope, $http) {
$http({
method: 'GET',
url: 'http://localhost:8000/api/order/?format=json'
}).then(function successCallback(response) {
console.log("OK Respone");
console.log(response.data);
$scope.orders = response.data;
}, function errorCallback(response) {
console.log("NO Response");
});
}]);
In the browser console, the object looks like this:
I would like some help to loop out and display whole the object in the .html file. My current code that does not work is currently looking like this:
<div ng-controller="ActiveController">
<div ng-repeat="order in orders">
<p>{{ order.id }}</p>
<p>{{ order.created }}</p>
</div>
</div>
I don't think I need to show my "main" .html file, so I'm not posting it.
The problem is in the controller. Try saving objects in $scope.orders
$scope.orders = response.data.objects;
You can fix this in the view and the controller as well:
In View as:
<div ng-controller="ActiveController">
<div ng-repeat="order in orders.objects"> <!-- note the orders.objects -->
<p>{{ order.id }}</p>
<p>{{ order.created }}</p>
</div>
</div>
In Controller as
$scope.orders = response.data.objects;
As rightly suggested by #ddepablo.
It will work fine.

Unable to ng-repeat directives in angularjs

I am new to angularjs. I want to dynamically add directives to a div based the titles from controller.. Below is what i tried...
Below is the directives and factory i used
QtTemplate.directive("shortanswer",function()
{
return{
restrict:"A",
templateUrl:'assets/directives/shortAnswer.html'
}
})
Template.factory("questionList",function()
{
var questionList={};
questionList.testid="1";
questionList.name="Maths";
questionList.Questions =
[
{"title":"truefalse"},
{"title":"shortanswer"}
]
return questionList;
})
Template.controller("questionControl",['$scope','questionList',function($scope,questionList)
{
$scope.name = questionList.name;
$scope.id = questionList.testid;
$scope.Questions = questionList.Questions;
}])
Template.directive('dynamicDirective',function($compile)
{
return {
restrict: 'A',scope:{},
replace: false,
terminal: true,
priority: 1000,
link:function(scope,element,attrs)
{
element.attr(scope.$eval(attrs.dynamicDirective),"");
element.removeAttr("dynamic-directive"); //remove the attribute to avoid indefinite loop
element.removeAttr("data-dynamic-directive");
$compile(element)(scope);
}
};
});
QtTemplate.directive("shortanswer",function()
{
return{
restrict:"A",
templateUrl:'assets/directives/shortAnswer.html'
}
})
Below is how i use ng-repeat
<div ng-repeat="Questions in Questions" >
<div dynamicDirective="{{Questions.title}}" ></div>
</div>
This is not working
use-kebab-case-in-html
<div ng-repeat="Question in Questions" >
<div dynamic-directive="{{Question.title}}" ></div>
</div>
You need to write dynamic-directive instead of dynamicDirective in your HTML. Camelcase in Javascript needs to be written as snakecase kebab-case in HTML.
Here you are:
<div ng-repeat="Question in Questions" >
<div dynamicDirective="{{Question.title}}" ></div>
</div>
Hope this helps.

AngularJs two-way-data-binding not working for custome directive input elements

I have created the custome directive for creating dynamic form elements based on backend data .I have created directive and template .Please find below my directive ,template and json string
angular.module('publicApp').directive('buildInput', function() {
return {
require: "ngModel",
restrict:"E",
scope:{
build:"=",
},
templateUrl:"views/directives/buildInput.html",
}
});
My template is
<label>{{build.reg_label}}
<span class="color-red">*</span>
</label>
<div ng-if="build.reg_type=='text'">
<input class="form-control" type="text" required="true" ng-model="buildData[build.id]">
</div>
<div ng-if="build.reg_type=='select'">
<select ng-options="reg_option.value as reg_option.label for reg_option in build.reg_options" ng-model="buildData[build.id]">
<option value="" ng-show="$first">-- {{build.reg_label}} --</option>
</select>
</div
>
view file is
<div class="form-group" ng-repeat="build in builds">
<build-input build="build" ></build-input>
</div>
My json string is
[
{
"id":"1",
"reg_label":"What is Your Name",
"reg_type":"text",
},
{
"id":"2",
"reg_label":"Select Gender",
"reg_options":[
{
"label":"Male",
"value":"M"
},
{
"label":"Female",
"value":"F"
}
],
"reg_type":"select",
}
]
why my modal not binding with scope variable buildData ?
Your directive only knows build variable since your (isolated) scope is defined like this:
scope:{
build:"=",
},
Sounds like your buildData variable is defined on the controller where builds is defined, so you should extend your scope to look like:
scope:{
build:"=",
buildData:"="
},
And your HTML directive declaration:
<build-input build="build" build-data="buildData" ></build-input>

How to bind and automatically update view when $scope is updated in 2 different controllers in Angularjs

Here is a fiddle: http://jsfiddle.net/a0eLhcbm/
I have a simple setup:
<div ng-app="demo" ng-controller="PageController">
{{ page.time }}
<div ng-controller="UsernameController">
{{ user.name }}
</div>
</div>
There is a function that will, say, get the user.name from somewhere else using ajax, and that function belongs to controller PageController.
Question: Is there anyway I can make the {{ user.name }} within the UsernameController to update itself as soon as the controller PageController receives the information?
Here is my javascript setup:
var app = angular.module( 'demo', [] );
function_that_fetches_for_username = function() {
//Some function that fetch for username asynchronously
};
app.controller( 'PageController', function ( $scope ) {
//Initial data
$scope.page = {};
$scope.page.time = Date();
function_that_fetches_for_username();
//How can I make the UsernameController to update its view from this Controller as soon as this controller receives the information?
});
app.controller( 'UsernameController', function( $scope ) {
//Initial data
$scope.user = {};
$scope.user.name = "";
//How can I automatically updated the $scope.user.name in view as soon as the PageController receives the information about the username?
});
There are probably a lot of ways to solve this problem, my share to this is to use either of the two below:
[1] Create a service that you can share to any part of your application (Controllers, Services, Directives, and Filters).
In relation to your problem, you can simply create a User service that can be shared across your controllers. The solution below assumes that the function_that_fetches_for_username() is a service UserResource that has a method get() that simulates fetching data from a server. The User service is an empty object that is shared across all your controllers.
DEMO
JAVASCRIPT
angular.module('demo', [])
.service('UserResource', function($timeout) {
this.get = function() {
return $timeout(function() {
return {
id: 'w3g45w34g5w34g5w34g5w3',
name: 'Ryan'
};
}, 2000);
};
})
.service('User', function() {
return {};
})
.controller('PageController', function($scope, UserResource, User) {
$scope.page = {
time: Date()
};
UserResource.get().then(function(data) {
angular.extend(User, data);
});
})
.controller('UsernameController', function($scope, User) {
$scope.user = User;
});
HTML
<div ng-app="demo" ng-controller="PageController">
{{ page.time }}
<hr>
<div ng-controller="UsernameController">
<div ng-if="user.name">
{{ user.name }}
</div>
<div ng-if="!user.name" style="color: red">
Waiting for Response...
</div>
</div>
</div>
[2] Use the controllerAs syntax for declaring controllers. Use this type of notation for child controllers to access parent controllers using their aliases.
DEMO
JAVASCRIPT
angular.module('demo', [])
.service('UserResource', function($timeout) {
this.get = function() {
return $timeout(function() {
return {
id: 'w3g45w34g5w34g5w34g5w3',
name: 'Ryan'
};
}, 2000);
};
})
.controller('PageController', function(UserResource) {
var ctrl = this;
ctrl.page = {
time: Date()
};
ctrl.user = {};
UserResource.get().then(function(data) {
angular.extend(ctrl.user, data);
});
})
.controller('UsernameController', function() {
this.getUser = function(user) {
console.log(user);
};
});
HTML
<div ng-app="demo" ng-controller="PageController as PC">
{{ PC.page.time }}
<hr>
<div ng-controller="UsernameController as UC">
<div ng-if="PC.user.name">
{{ PC.user.name }}
</div>
<div ng-if="!PC.user.name" style="color: red">
Waiting for Response...
</div>
<button type="button" ng-click="UC.getUser(PC.user)"
ng-disabled="!PC.user.name">
Access user from Page Controller
</button>
</div>
</div>
You can do one of these for sharing the same value through multiple controllers:
Promote the value to a higher level scope all the interested controllers have access to. Controllers will get it through scope inheritance because angular automatically searches the value through the scope hierarchy.
Whoever gets the value broadcasts it through the higher level scope all the controllers have access to. All the controllers listening for this broadcast will get the value.
you can define your user in pageController(that is parent controller to UsernameController) now whenever you change it in pageController it will also be updated in usernameController
second solution is to have ng-view in parent, and in route use controller for UsernameController
index file
<div ng-app="demo" ng-controller="PageController">
{{ page.time }}
<ng-view></ng-view>
</div>
user.html
<div ng-controller="UsernameController">
{{ user.name }}
</div>
route codee
.when("/user",{
controller:"usernameController",
templateUrl : 'user.html'
})
Third solution is to make a service
.factory("userFactory",function(){
var user = {};
return{
setUser : function(usern){
user = usern;
},
getUser : function(usern){
return user;
},
}
})
now you can get user from service and set to service .

Categories