Hi guys I have a very complicated issue.
I have created a reusable directive and now i want to take the user's parameter value and bind it to my form inside the directive.
At the user's side, they are able to call the directive by:
<test-app></test-app>
Then they are able to pass in parameters into the directive :
<test-app user-email="test#hotmail.com"></test-app>
OR
<test-app user-email="{{ userEmail }} "></test-app>
//They can take value from their own controller.
At my Own side at the directive , main.js :
angular.module('TestModule').controller('MainCtrl',['$mdDialog',function($mdDialog) {
this.openDialog = openDialog;
function openDialog(){
$mdDialog.show({
controller: 'DialogCtrl as dialog',
templateUrl: 'dialog.html'
});
}
}]);
angular.module('TestModule').directive('testApp',function(){
return {
controller: 'MainCtrl as main',
scope: {
userEmail :'#'
},
restrict : 'E' ,
templateUrl : 'FormButton.html'
}
});
angular.module('TestModule').controller('DialogCtrl',['$mdDialog',function($mdDialog,$scope){
function submit(){
etc etc . .
}
}
At the FormButton.html:
<md-button ng-click="main.openDialog()"> </md-button>
At the dialog.html:
<md-dialog>
<form>
etc , etc
<input type="email" name="email" placeholder="Email" data-ng-model="userEmail">
etc , etc
</form>
</md-dialog>
Issue: I need to pass in the userEmail value from the user side and bind it to the form so that when the user opens the form , the value is there.
I think because of the templateUrl , the convention way of binding the model doesn't work.
What i have tried:
1) I tried ng-model to bind but the form is in another page so it was not able to read the value.
2) I wanted to pass the value from the directive to controller , I research online but found no viable solution to this problem.
can anyone Kindly Help with this solution?
Take a look at the $mdDialog api docs, especially at the locals option.
locals - {object=}: An object containing key/value pairs. The keys
will be used as names of values to inject into the controller. For
example,
this.userEmail = 'someone#neeae.com';
function openDialog(){
$mdDialog.show({
controller: 'DialogCtrl as dialog',
templateUrl: 'dialog.html',
locals: {
email: this.userEmail // `this` is the main controller (parent).
}
});
}
In the html:
<test-app user-email="{{ main.userEmail }} "></test-app>
DialogCtrl
angular.module('TestModule').controller('DialogCtrl', ['$mdDialog', '$scope', 'email', function($mdDialog, $scope, email) {
// Here you can use the user's email
this.userEmail = email;
function submit() {
//etc etc ..
}
}]);
At the dialog.html:
<md-dialog>
<form>
<!-- etc , etc-->
<input type="email" name="email" placeholder="Email" data-ng-model="dialog.userEmail">
<test-app email="test#hotmail.com"></test-app>
You are passing value in "email" variable. But you are not mapping this variable in directive scope.
Try this once.
<test-app userEmail="test#hotmail.com"></test-app>
Related
I am using an Angular 1.5 Material Design $mdDialog in the recommended way, using controllerAs: "dialog". In the template I have a form: <form name="fooForm". Within the template I can access the form with no problem, e.g. ng-disabled="fooForm.$invalid || fooForm.$submitted".
But how do I access that form from within the $mdDialog controller? From what I read, I would expect to be able to do this:
const doFoo = () => {
if (this.fooForm.$dirty) {
Here this is the dialog controller.
But I get an error: TypeError: Cannot read property '$dirty' of undefined. And sure enough, if I put a breakpoint in the code, the controller has no fooForm property.
I've tried using $scope as well, but when I put a breakpoint in the code $scope has no fooForm property either.
Here's my dialog template:
<md-dialog aria-label="FooBar">
<md-toolbar>
<div class="md-toolbar-tools">
<h2>FooBar</h2>
<span flex></span>
<md-button class="md-icon-button" ng-click="dialog.cancel()">
<md-icon>close</md-icon>
</md-button>
</div>
</md-toolbar>
<form name="fooForm" ng-submit="dialog.ok()" novalidate>
<md-dialog-content>
<div layout="column" layout-padding>
<h2 class="md-headline">Foo</h2>
<div layout="row" layout-xs="column">
...
</div>
</md-dialog-content>
<md-dialog-actions>
<md-button class="md-primary" type="submit" ng-disabled="fooForm.$invalid || fooForm.$submitted">
OK
</md-button>
<md-button ng-click="dialog.cancel()">
Cancel
</md-button>
</md-dialog-actions>
</form>
</md-dialog>
How do I access a form in an $mdDialog from the dialog controller?
you need to assign the form to the Scope of the Controller. Do this by changing the form name from fooForm to dialog.fooForm.
<form name="dialog.fooForm" ng-submit="dialog.ok()" novalidate>
Scope existed and still exist disregarding controllerAs. When you use 'controllerAs xxx' that just mean - put my controller into scope and name it xxx. You can use them together:
function controller($scope) {
var vm = this;
vm.click = function() {}
$scope.click = function() {}
}
<button ng-click="xxx.click()" ...
<button ng-click="click()" ...
Now if you write ng-click="whatever();smth();"angular will use $parse(expression)(scope) to parse this expression.
Now you write form name="formName" -- angular will use $parse("formName").assign(scope, form); and put it to scope.
$parse is quite clever and can easily handle nested properties, to put form to your controller (as xxx): <form name="xxx.myForm"></form>
The form is not defined in your controller as a property and therefore you cannot access the form like if (this.fooForm.$dirty).
However you can easily pass it to your method:
const doFoo = (fooForm) => {
if (fooForm.$dirty) {
...
And in html:
ng-click="dialog.cancel(fooForm)"
Give your controller name when your $mdDialog initialize. see below code:
$scope.showDialog = function (ev) {
$mdDialog.show({
controller: 'myController',
templateUrl: 'template.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: false,
fullscreen: false // Only for -xs, -sm breakpoints.
})
.then(function (answer) {
$scope.status = 'You said the information was "' + answer + '".';
}, function () {
$scope.status = 'You cancelled the dialog.';
});
};
Make sure you put controller name in quotes when you create separate controller. like controller: 'myController'
if you want to pass a function then not quotes needed like controller: myController,
In html template use ng-submit="ok()" instead of ng-submit="dialog.ok()".
I have created a sample plnkr with your template and it is working fine. check here
EDIT :`
angular.module('BlankApp', ['ngMaterial']).controller('myController', function($scope, $mdDialog) {
$scope.ok = function () {
if ($scope.fooForm.$dirty) {
// do whatever you want
$mdDialog.hide("mesage");
}
};
});`
My Html:
<test-app email="hello#hotmail.com"></test-app>
My Directive:
.directive('testApp', function () {
return {
restrict: 'E',
scope: {
userEmail = '#userEmail'
},
templateUrl: 'Form.html'
};
})
My Form in another Page:
<label> Email </label>
<input type="text" id="email">
Issue: I need to get the parameter value , and print it out on the textbox itself.
What i have done: I research on a lot of articles which demonstrated on how to pass directive parameters to controller but they were very complicated.
What i think is the next step:
1) Pass the directive parameter to the controller and then bind the controller to the textbox and set the value of the textbox to be the parameter value.
2) Or is there another way i can do this?
I am stuck on how to proceed on.
You can use attribute string binding using #
In controller you initialize your userEmail variable
The directive has a user-email attribute which loads value into the directive's userEmail local scope variable.
Using userEmail:'#' allows for string binding from controller to the directive.
See demo below:
angular.module("app",[]).directive('application', function() {
return {
restrict: 'E',
scope: {
userEmail : '#'
},
templateUrl: 'Form.html'
};
}).controller("ctrl",function($scope){
$scope.userEmail="hello#hotmail.com";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<application user-email="{{userEmail}}"></application>
<script type="text/ng-template" id="Form.html">
<label>Email</label>
<input type="text" id="email" ng-model="userEmail">
</script>
</div>
I am trying to populate the ng-model from a value, but don't want it to update until it is saved. To do this I have the following code;
Controller;
var SettingsController = function (roleService) {
var ctrl = this;
ctrl.rename = function(name) {
ctrl.account.name = name;
};
roleService.role.settings().then(function (result) {
ctrl.account = result.data.account;
}, function (result) {
console.log(result);
});
};
A simple controller, it gets the current settings from a service and sets it to the ctrl.
When the rename(name) is called I update the name of the account (for now it just updates the scope but soon it will update also the back-end)
To rename your account I have the following piece of code
<input type="text" data-ng-model="account.name" />
<button type="button" data-ng-click="ctrl.rename(account.name)">
Rename
</button>
I use controler as so ctrl == SettingsController
Now I use data-ng-model="account.name" to update the name. This is done so I only update the name when the button is called. The only issue is how do I get the ctrl.account.name value to the input, without bubbling it up.
I could add $scope to my controller with $scope.account but that seems overkill to me. Isn't there a way to copy/populate a ng-model from an other value or some kind?
To get to the controller I use the angular routerProvider;
$routeProvider
.when('/settings/', {
templateUrl: '/user/template/settings/',
controller: 'SettingsController',
controllerAs: 'ctrl'
});
I have angular working in one of my ASP.NET MVC applications. I am using two html templates with Angular Routing. One is a list of current Favorites that comes from the database and is serialized into json from my Web API and used by angular to list those items from the database.
The second html template is a form that will be used to add new favorites. When the overall page that includes my angular code loads, it has a cookie named currentSearch which is holding the value of whatever the last search parameters executed by the user.
I would like to inject this value into my angular html template (newFavoriteView.html) for the value of a hidden input named and id'd searchString.
I have tried using jQuery, but had problems, plus I would much rather do this inside of angular and somehow pass the value along to my template or do the work inside the view(template). However, I know the latter would be bad form. Below is the code I think is important for one to see in order to understand what I am doing.
Index.cshtml (My ASP.NET VIEW)
#{
ViewBag.Title = "Render Search";
ViewBag.InitModule = "renderIndex";
}
<div class="medium-12 column">
<div data-ng-view=""></div>
</div>
#section ngScripts {
<script src="~/ng-modules/render-index.js"></script>
}
Setting the cookie in the MVC Controller
private void LastSearch()
{
string lastSearch = null;
if (Request.Url != null)
{
var currentSearch = Request.Url.LocalPath + "?" +
Request.QueryString;
if (Request.Cookies["currentSearch"] != null)
{
lastSearch = Request.Cookies["currentSearch"].Value;
ViewBag.LastSearch = lastSearch;
}
if (lastSearch != currentSearch)
{
var current = new HttpCookie("currentSearch", currentSearch){
Expires = DateTime.Now.AddDays(1) };
Response.Cookies.Set(current);
var previous = new HttpCookie("lastSearch", lastSearch) {
Expires = DateTime.Now.AddDays(1) };
Response.Cookies.Set(previous);
}
}
}
render-index.js
angular
.module("renderIndex", ["ngRoute"])
.config(config)
.controller("favoritesController", favoritesController)
.controller("newFavoriteController", newFavoriteController);
function config($routeProvider) {
$routeProvider
.when("/", {
templateUrl: "/ng-templates/favoritesView.html",
controller: "favoritesController",
controllerAs: "vm"
})
.when("/newsearch", {
templateUrl: "/ng-templates/newFavoriteView.html",
controller: "newFavoriteController",
controllerAs: "vm"
})
.otherwise({ redirectTo: "/" });
};
function favoritesController($http) {
var vm = this;
vm.searches = [];
vm.isBusy = true;
$http.get("/api/favorites")
.success(function (result) {
vm.searches = result;
})
.error(function () {
alert('error/failed');
})
.then(function () {
vm.isBusy = false;
});
};
function newFavoriteController($http, $window) {
var vm = this;
vm.newFavorite = {};
vm.save = function () {
$http.post("/api/favorites", vm.newFavorite)
.success(function (result) {
var newFavorite = result.data;
//TODO: merge with existing topics
alert("Thanks for your post");
})
.error(function () {
alert("Your broken, go fix yourself!");
})
.then(function () {
$window.location = "#/";
});
};
};
favoritesView.html
<div class="container">
<h3>New Favorite</h3>
<form name="newFavoriteForm" ng-submit="vm.save()">
<fieldset>
<div class="row">
<div class="medium-12 column">
<input name="searchString" id="searchString" type="hidden"
ng-model="vm.newFavorite.searchString"/>
<label for="title">Name</label><br />
<input name="title" type="text"
ng-model="vm.newFavorite.name"/>
<label for="title">Description</label><br />
<textarea name="body" rows="5" cols="30"
ng-model="vm.newTopic.description"></textarea>
</div>
<div class="medium-12 column">
<input type="submit" class="tiny button radius" value="Save"/> |
Cancel
</div>
</div>
</fieldset>
</form>
</div>
My current attepts have been using jQuery at the end of the page after Angular has loaded and grab the cookie and stuff it in the hidden value. But I was not able to get that to work. I also thought about setting the value as a javascript variable (in my c# page) and then using that variable in angular some how. AM I going about this the right way?
Or should it be handled in the angular controller?...
I'm new to angular and the Angular Scope and a bit of ignorance are getting in the way. If any other info is needed I can make it available, thanks if you can help or guide me in the right direction.
You can do it by reading the cookie value using JavaScript, set it as a property of the $scope object and access it on the template.
//Inside your controllers
function favoritesController($http, $scope) {
//Get the cookie value using Js
var cookie = document.cookie; //the value is returned as a semi-colon separated key-value string, so split the string and get the important value
//Say the cookie string returned is 'currentSearch=AngularJS'
//Split the string and extract the cookie value
cookie = cookie.split("="); //I am assuming there's only one cookie set
//make the cookie available on $scope, can be accessed in templates now
$scope.searchString = cookie[1];
}
EXTRA NOTE
In AngularJS, the scope is the glue between your application's controllers and your view. The controller and the view share this scope object. The scope is like the model of your application. Since both the controller and the view share the same scope object, it can be used to communicate between the two. The scope can contain the data and the functions that will run in the view. Take note that every controller has its own scope. The $scope object must be injected into the controller if you want to access it.
For example:
//inject $http and $scope so you can use them in the controller
function favoritesController($http, $scope) {
Whatever is stored on the scope can be accessed on the view and the value of a scope property can also be set from the view. The scope object is important for Angular's two-way data binding.
Sorry if I'm misunderstanding or over-simplifying, but...assuming JavaScript can read this cookie-value, you could just have your controller read it and assign it to a $scope variable?
If JavaScript can't read the value, then you could have your ASP write the value to a JavaScript inline script tag. This feels yuckier though.
Update to show controller-as example.
Assuming your HTML looked something vaguely like this:
<div ng-controller="MyController as controller">
<!-- other HTML goes here -->
<input name="searchString" id="searchString" type="hidden" ng-model="controller.data.currentSearch"/>
Then your controller may look something like this:
app.controller('MyController', function ($scope, $cookies) {
$scope.data = {
currentSearch: $cookies.currentSearch
};
// Note that the model is nested in a 'data' object to ensure that
// any ngIf (or similar) directives in your HTML pass by reference
// instead of value (so 2-way binding works).
});
In my angular app I have a product view/controller that has the common questions for product (SKU, Name, Description etc). I also have a dropdown field named ProductType that I will use to load a dynamic view/js/controller for questions that vary based on that product type. When the user saves the product I'll have a property on the base product model named ProductTypeConfig (as well as ProductType) that contains a json representation of the product type configuration and I want to pass all that to the server controller for persistence.
Has anyone seen this done before in Angular? Comments or clues as to how to go about this? I don't want to load all of js for every product type controller etc. ahead of time as this will potentially be plugable by the client as new product types are rolled out.
EDIT:
Ok, so I created a plunk to demonstrate what I'm trying to accomplish. I have the dynamic piece working well I think. At this point I just need to figure out how to grab the dynamic data in the saveProduct() function in the ProductController. When save is clicked, I need to somehow call a method on either the TypeAController or the TypeBController depending on which one is loaded. I was thinking that I could probably create a service that all the controllers would depend on and have it do the work. Is this something that is possible?
The plunk is located here http://plnkr.co/edit/6kQYKU
This is the main controller:
(function() {
var app = angular.module('ProductApp', ['ngRoute']);
app.config(function($httpProvider, $routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'product.html',
controller: 'ProductController'
}).
otherwise({
redirectTo: '/'
});
});
var ProductController = function($scope, $log, $routeParams, $location) {
var saveProduct = function() {
// how to get data from either TypeAController or TypeBController here when saved from ProductController
$log.log('Product saved')
$location.path('/');
};
$scope.saveProduct = saveProduct;
// values
$scope.ProductId = 1001;
$scope.Name = 'Product 1001';
$scope.Type = 'typea';
};
app.controller("ProductController", ProductController);
}());
And this is one of the dynamic views with it's controller:
<div ng-controller='TypeAController'>
<h1>Type A Settings</h1>
<fieldset>
<div class="dnnFormItem">
<label>Width:</label>
<br />
<input type="text" name="width" ng-model="Width" />
<br />
<label>Height:</label>
<br />
<input type="text" name="height" ng-model="Height" />
<br />
</div>
</fieldset>
</div>
<script>
console.log('TypeA is loaded');
var TypeAController = function($scope, $log) {
};
angular.module('ProductApp').controller("TypeAController", TypeAController);
</script>
I ended up doing a simple factory to share an object between controllers as demonstrated in this plunk, http://plnkr.co/edit/6kQYKU. This also demonstrates loading a dynamic view based on a field in the parent view.
var stateService = function() {
'use strict';
var state = {};
return {
state: state,
};
};
app.factory('StateService', stateService);