I am new to AngularJS, Somehow while going through many sites now I am able to create a directive for showing some data.Now I need to send some data to controller by clicking the button. I need to know the proper way of doing this
I have created the plunk
html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="jquery#*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="movieDesc">
<div ng-repeat="m in movies" movies="m"></div>
</body>
</html>
Directive and Controller
// Code goes here
angular.module('app', []);
angular.module('app').controller('movieDesc', function($scope) {
$scope.movies = [{
name: 'abc',
desc: 'this is desc text for the movie',
pic: 'http://png.clipart.me/graphics/thumbs/134/abstract-geometric-background-triangle-and-square-black_134053397.jpg'
}, {
name: 'def',
desc: 'this is desc text for the movie def',
pic: 'http://png.clipart.me/graphics/thumbs/201/abstract-modern-banner-background-of-geometric-shapes-abstract-geometric-form_201768245.jpg'
}, {
name: 'ghi',
desc: 'this is desc text for the movie ghi',
pic: 'http://www.cianellistudios.com/images/abstract-art/abstract-art-infinite-150.jpg'
}]
$scope.saveData = function(data) {
console.log(data);
}
});
angular.module('app').directive('movies', function() {
return {
templateUrl: "movieCard.html",
restrict: "EA",
scope: {
movies: '='
},
link: function(scope, element, attrs) {
element.addClass('moviesBox');
var clickedFn = function() {
alert("clicked");
};
console.log("console", element[0].querySelector('.btnSelect'));
var $this = element[0].querySelector('.btnSelect');
$($this).click(function() {
alert(scope.movies.desc)
})
}
}
})
My Template
<div>
<div>
<b>Name:</b> {{movies.name}}
</div>
<div>
<b>Description:</b> {{movies.desc}}
</div>
<div>
<img src="{{movies.pic}}" />
</div>
<div>
<input type="text" ng-model="movies.someText">
</div>
<div>
<input class="btnSelect" type="button" value="Desc" ng-click="clickedFn()">
</div>
<div>
<input class="btnSelect" type="button" value="Save Data" ng-click="saveData({{movies}})">
</div>
</div>
I need to send the data to the controller's $scope.saveData() function, the data will be entered through the textbox. I have given it as ng-model="movies.someText" which I suppose is the wrong way.
So please help me.
Use the & scope binding.
scope: {
movies: '=',
save: '&'
},
and in the directive template
<input type="button" ng-click="save({movie: movies})" ...>
You then bind the controller method via
<div ng-repeat="m in movies" movies="m" save="saveData(movie)"></div>
Note the argument name passed to the controller function matches the object key in the directive template.
https://plnkr.co/edit/9bF5FDea6wLn7vcGvEzU?p=preview
While you're there, use ng-src instead of src to avoid a 404 request for a non-existent image
<img ng-src="{{movies.pic}}" />
html
<body ng-controller="movieDesc">
<div ng-repeat="m in movies" movies="m">
<movies-dir
movies="m" save-data="saveData(movie)"></movies-dir>
</div>
</body>
Directive and Controller
angular.module('app', []);
angular.module('app')
.controller('movieDesc', function($scope) {
$scope.movies = [/* movie object array data */]
$scope.saveData = function(movie) {
console.log(movie);
}
});
angular.module('app').directive('moviesDir', function() {
return {
templateUrl: "movieCard.html",
restrict: "EA",
scope: {
movies: '=',
saveData: '&'
},
link: function(scope, element, attrs) {
}
}
})
Template
<div>
<input class="btnSelect" type="button" value="Save Data" ng-click="saveData({ 'movie': movies })">
</div>
You need to pass saveData as a parameter like this:
<body ng-controller="movieDesc">
<div ng-repeat="m in movies" movies="m" save-data="saveData()"></div>
And you get back in your directive like this:
return {
templateUrl: "movieCard.html",
restrict: "EA",
scope: {
movies: '=',
saveData:'='
},
link: ...
And then in your template.html, you don't need to use '{{}}' :
<input class="btnSelect" type="button" value="Save Data" ng-click="saveData(movies)">
Related
In my current project I need to create a dynamic form using AngularJS.
I am already building the form following the ideas from this video here.
I can't seem to get the submitted data back to my controller. I only receive undefined in the console log.
Currently the data for the form is resolved in ui-router before the state is loaded, then copied to the controller's data property.
Unlike the video our form requires that questions are broken down into sections.
There is a ng-repeat over each section in the data, then a nested ng-repeat goes over each question. The type is determined and the proper directive for the question/field type is loaded to via ng-switch.
I whipped up a small Plunker to help illustrate as well.
https://plnkr.co/edit/6dCnHiFDEYu03kfX07mr
Finally there are some types I am unsure how to handle, such as address or phone number which will be considered one question type but have multiple fields.
(e.g. [Street] [City] [State] [Zip])
Controller
namespace portal.dashboard.form{
class formCtrl{
formData: portal.domain.interfaces.IHousingRequest;
static $inject = ["formResolve"];
constructor(private formResolve:any) {
this.formData= this.loadHousingRequestFormData;
}
public submit(isValid,data) {
if (isValid) {
console.log(data);
}
}
}
angular
.module("portal")
.controller("formCtrl", formCtrl);
}
Directive for input type text
namespace portal.directives {
function inputText(): ng.IDirective {
return {
scope: {
model: '='
},
controller: function ($scope: ng.IScope) {
var directiveScope = $scope.$parent.$parent;
},
controllerAs:'vm',
templateUrl: 'form/templates/input-text.html'
}
}
angular
.module("portal")
.directive("inputText", inputText);
}
input type html
<input type="text"
ng-model="model"/>
HTML
<form name="form" ng-submit="vm.submit(form.$valid, data)" novalidate>
<!-- Section repeat -->
<div ng-repeat="section in vm.formData.sections track by $index">
<section>
<div>
<h4>
{{section.name}}<br />
<small ng-show="section.description">{{section.description}}</small>
</h4>
</div>
<section>
<!-- Section questions repeat -->
<div ng-form="formFields" ng-repeat="field in section.fields track by $index">
<label>
{{field.name}}<br />
<small>{{field.description}}</small>
</label>
<!-- input field switch -->
<div ng-switch="field.type">
<div ng-switch-when="Text">
<input-text model="data.answer[$index]">
</input-text>
</div>
<div ng-switch-when="Email">
<input-email model="data.answer[$index]">
</input-email>
</div>
</div>
</div>
</section>
</section>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
You have to init $scope.data = {}; before using it, also use correct sectionIndex and fieldIndex to populate the answer:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.data = {};
$scope.sections = [{
name: 'User Info',
description: 'I\'m a description.',
fields: [{
label: "Name",
type: "text"
}, {
label: "Email",
type: "email"
}]
}, {
name: 'Pet Info',
description: '',
fields: [{
label: "Pet Breed",
type: "text"
}]
}];
$scope.submit = function(isValid, data) {
console.log('submit fired');
if (isValid) {
console.log(data);
}
}
});
app.directive('inputText', function() {
return {
scope: {
model: '='
},
controller: function($scope) {
var directiveScope = $scope.$parent.$parent;
},
controllerAs: 'vm',
template: '<input type="text" ng-model="model"/>'
}
});
app.directive('inputEmail', function() {
return {
scope: {
model: '='
},
controller: function($scope) {
var directiveScope = $scope.$parent.$parent;
},
controllerAs: 'vm',
template: '<input type="email" ng-model="model"/>'
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<body ng-app="plunker" ng-controller="MainCtrl">
<form name="form" ng-submit="submit(form.$valid, data)" novalidate>
<!-- Section repeat -->
<div ng-repeat="(sectionIndex, section) in sections track by $index">
<section>
<div>
<h4>
{{section.name}}<br />
<small ng-show="section.description">{{section.description}}</small>
</h4>
</div>
<section>
<!-- Section questions repeat -->
<div ng-form="formFields" ng-repeat="(fieldIndex, field) in section.fields track by $index">
<label>
{{field.label}}<br />
</label>
<!-- input field switch -->
<div ng-switch="field.type">
<div ng-switch-when="text">
<input-text model="data.answer[sectionIndex][fieldIndex]">
</input-text>
</div>
<div ng-switch-when="email">
<input-email model="data.answer[sectionIndex][fieldIndex]">
</input-email>
</div>
</div>
</div>
</section>
</section>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</body>
Also I'm not sure why do you need this var directiveScope = $scope.$parent.$parent; in your directive's controller, do you really need this?
I'm trying really hard, but I can't find where is my problem.
I created a custom directive and it should iterate some HTML to draw the right content on the screen.
The problem is that my ng-repeat does not iterate my array. I search on stackoverflow but what I found didn't help me.
Here is my directive (it's in an external file):
app.directive('logtab', function(){
return {
restrict: 'E',
templateUrl: 'view/templates/log-tab.html',
replace: true,
controller: ['$scope', 'api', function($scope, api) {
$scope.logState = false;
$scope.logData = [1,2,3,4];
$scope.loadLog = function() {
api.doRequest({
path : $scope.path,
method : "GET",
broadcast : BK_LOG
});
};
var bk = $scope.$on(BK_LOG, function(key, value){
$scope.logState = true;
console.log($scope.logData);
bk();
});
}]
};
});
And here is the directive HTML that will be rendered:
<md-tab ng-click="loadLog()" label="{{i18n['REVISIONS']}}">
<div layout="row" layout-align="center" layout-padding ng-show="!logState">
<div layout="column">
<div>
<md-progress-circular md-mode="indeterminate" md-diameter="130"></md-progress-circular>
</div>
<div>
{{i18n['LOG_LOAD']}}
</div>
</div>
</div>
<div layout="row" ng-show="logState" layout-padding>
<div layout="column">
<div ng-repeat="xyz in logData">
{{xyz}}
SOME CONTENT HERE
</div>
</div>
</div>
</md-tab>
Thanks in advance!
I removed other components from your directive code and kept it at bare minimum. The code is working fine as expected. Please see below.
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body ng-app="myApp" >
<logtab></logtab>
<script src="angular.js" type="text/javascript "></script>
<script src="app.js" type="text/javascript "></script>
</body>
</html>
app.js
var myApp = angular.module('myApp', []);
myApp.directive('logtab', function(){
return {
restrict: 'E',
templateUrl: 'log-tab.html',
replace: true,
controller: ['$scope', function($scope) {
$scope.logState = false;
$scope.logData = [1,2,3,4];
console.log('hi');
}]
};
});
log-tab.html
<div>
{{logData}}
<div layout="row">
<div layout="column">
<div ng-repeat="xyz in logData">
{{xyz}}
</div>
</div>
</div>
</div>
Please use a couple of console.log's to identify the exact location. I suspect that there must be some thing wrong with the other parts of the directive or may be logState is set to false??
You can always separate the controller from the directive:
app.directive('logtab', function(){
return {
restrict: 'E',
templateUrl: 'view/templates/log-tab.html',
replace: true,
scope: {
log: '='
}
};
});
Then in your controller
app.controller('MyController', ['$scope', 'api', function($scope, api) {
$scope.logTab = {
state: false,
data: [1, 2, 3, 4],
loadLog: function() {
api.doRequest({
path : $scope.path,
method : "GET",
broadcast : BK_LOG
});
}
};
var bk = $scope.$on(BK_LOG, function(key, value){
$scope.logTab.state = true;
console.log($scope.logTab.data);
bk();
});
}]);
Then change your HTML to:
<md-tab ng-click="log.loadLog()" label="{{i18n['REVISIONS']}}">
<div layout="row" layout-align="center" layout-padding ng-show="!log.state">
<div layout="column">
<div>
<md-progress-circular md-mode="indeterminate" md-diameter="130"></md-progress-circular>
</div>
<div>
{{i18n['LOG_LOAD']}}
</div>
</div>
</div>
<div layout="row" ng-show="log.state" layout-padding>
<div layout="column">
<div ng-repeat="xyz in log.data">
{{xyz}}
SOME CONTENT HERE
</div>
</div>
</div>
</md-tab>
And call it with
<logtab log="logTab"></logtab>
Updated my answer based on OP's explanation.
Created a fiddle here: https://jsfiddle.net/frishi/bzbbo5da/14/
I simplified the directive definition a little, removed the api part of it.
I also changed the directive's template to include the ng-repeat part of it.
//....
restrict: 'E',
template: `<p><div ng-repeat="xyz in logData">
{{xyz}}
SOME CONTENT HERE
</div></p>`,
replace: false,
scope: true, // <- needs to be set
//....
You are missing the scope parameter in the directive definition object. You have to set it to scope: true for your directive's template to be able to access a variable defined on the directive controller's scope.
Question: Why doesn't my simple directive have access to its controller when the element is used on certain pages?
Additional Info: The directive works on the main page. The HTML I could not use my directive on is called using ui-view and is included below.
<div ui-view></div>
Directive:
var postcardAppDirectives = angular.module('postcards.directives', ['postcards.controllers']);
postcardAppDirectives.directive('postcardLink', function () {
return {
restrict: "AE",
template: '<div class="well">{{ ctrl.ownerObj.user }}</div>',
controller: 'postcardLinkController as ctrl'
}
});
Controller:
var PostcardsControllers = angular.module('postcards.controllers', ['postcards.factories', 'postcards.services']);
PostcardsControllers.controller('postcardLinkController', [function ()
this.ownerObj = {
"user": 'test_owner',
"pointofthis": 'inane testing'
}
}]);
HTML (Does Not Work):
<div ng-controller="DashboardAccountController as infoCtrl" class="container full-container">
<!------------------ DIRECTIVE REFERENCE HERE -------->
<postcard-link></postcard-link>
<h1>
<small>Welcome</small>
<username-text></username-text>
</h1>
<img ng-show="infoCtrl.user.member_profile.profile_image" ng-src="{{ infoCtrl.user.member_profile.profile_image }}"
style="min-height:100px;height:100px;" alt='profileImage'/>
<button type="button" class="btn btn-link col-md-offset-2" ng-click="infoCtrl.loadPage()">Modify Account</button>
<div class="row">
...
HTML (Working Fine)
<ng-include src="'static/app/carousel/_carousel.html'"></ng-include>
<postcard-link></postcard-link>
<div class="container">
<section style="text-align: center">
<h1>How It Works</h1>
I see you used different module that's why one module don't know another module directive. you should use same module.
Like:
js:
var app = angular.module('postcards', []);//add dependencies in []
app.directive('postcardLink', function () {
return {
restrict: "AE",
template: '<div class="well">{{ ctrl.ownerObj.user }}</div>',
controller: 'postcardLinkController as ctrl'
}
});
app.controller('postcardLinkController', [function () {
this.ownerObj = {
"user": 'test_owner',
"pointofthis": 'inane testing'
}
}]);
use as usual html:
<postcard-link></postcard-link>
I have this directive:
App.directive('typeahead', function($timeout) {
return {
restrict: 'AEC',
scope: {
items: '=',
prompt:'#',
title: '#',
subtitle:'#',
model: '=',
selindex: '=',
onSelect:'&'
},
link:function(scope,elem,attrs){
scope.handleSelection=function(selectedItem){
scope.model=selectedItem;
scope.current=0;
scope.selected=true;
$timeout(function(){
scope.onSelect();
},200);
};
scope.current=0;
scope.selected=true;
scope.isCurrent=function(index){
return scope.current==index;
};
scope.setCurrent=function(index){
scope.current=index;
};
},
templateUrl: 'templates/templateurl.html'
}
});
I have this html:
<typeahead items="items" prompt="Start typing a US state" title="name" subtitle="id" model="name" on-select="onItemSelected()"/>
Directice is using this template:
<input type="text" ng-model="model" placeholder="{{prompt}}" ng-keydown="selected=false"/><br/>
<div class="items" ng-hide="!model.length || selected">
<div class="item" ng-repeat="item in items | filter:model track by $index" ng-click="handleSelection(item[subtitle])" style="cursor:pointer" ng-class="{active:isCurrent($index)}" ng-mouseenter="setCurrent($index)">
<p class="title">{{item[title]}}</p>
<p class="subtitle">{{item[subtitle]}}</p>
</div>
This calls the function in the directive:
scope.handleSelection=function(selectedSubtitle){
What I try to achieve is to call:
handleSelection(item[title], item[subtitle])
And pick it up in the directive like this:
scope.handleSelection=function(selectedTitle, selectedSubtitle){
However, the selectedSubtitle in the directive remains empty. How can I pass the additional parameter to the directive?
In my directive the example I was looking at here uses <a href="#" ... to put the new image in the container div. I've tried to create that same functionality in my directive but when I click my images it doesn't change my pictBox div. Could I be missing stuff in my css file? Why is the background-image text there? This is my directive:
app.directive('smallPictureBox', [function(){
return {
restrict: 'CA',
replace: false,
transclude: false,
scope: {
index: '=index',
item: '=itemdata'
},
template: '<img src="{{item.url}}"/>',
link: function(scope, elem, attrs) {
if (parseInt(scope.index)==0) {
angular.element(attrs.options).css({'background-image':'url('+ scope.item.url +')'});
}
elem.bind('click', function() {
var src = elem.find('img').attr('src');
angular.element(attrs.options).css({'background-image':'url('+ scope.item.url +')'});
});
}
}
}]);
This is what my html looks like:
<div class="shadow">
<div class="pictureBox">
<div id="pictBox">
<img ng-src="{{primaryImage.url}}">
</div>
</div>
<div class="lowerPictureBox">
<div ng-repeat="image in item.images" options='#pictBox' itemdata='image' index="$index" class="smallPictureBox">
<img ng-src="{{image.url}}">
</div>
</div>
</div>
How can make it so that when I click a picture in the lowerPictureBox it displays it in the pictureBox?
Although i could not replicate your total example but i have a set up a small working code which displays image on top when u click bottom image this could help you
<!DOCTYPE html>
<html ng-app="demo">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js"></script>
</head>
<body ng-controller="main">
<div class="shadow">
<div class="pictureBox">
<div id="pictBox">
<img ng-src="{{primaryImage.url}}">
</div>
</div>
<div class="lowerPictureBox">
<div small linksrc="primaryImage"></div>
</div>
</div>
<script>
var app = angular.module("demo", []);
app.controller('main', function ($scope) {
$scope.primaryImage = { url: '' };
});
app.directive('small', [function () {
return {
scope: { src: '=linksrc' },
replace:true,
template:"<img ng-src='http://angularjs.org/img/AngularJS-small.png'>",
link: function (scope, elem, attrs) {
elem.bind("click", function () {
scope.src.url = 'http://angularjs.org/img/AngularJS-small.png';
scope.$apply();
});
}
}
}]);
</script>
</body>
</html>