creating dynamic html emails with angularJS and mail with php - javascript

I have been trying to solve this and have been looking everywhere. Apologies in advance if this sounds stupid or there is a duplicate question somewhere that I have missed.
I am trying to create dynamic email content and send the email via php mail. I want to use angularJS to compile the html content and using $http.post method send to a submit.php to send email.
I can manually enter in the html content in php and no problem but having a compiled dynamic html is the issue.
I am really not too sure how to tackle this, so any help would be much appreciated.
Thanks,
My angular controller:
$scope.url = 'submit.php';
$scope.formsubmit = function(isValid) {
if (isValid) {
$http.post($scope.url, {"name": $scope.name, "email": $scope.email, "message": $scope.message }).
success(function(data, status) {
console.log(data);
$scope.status = status;
$scope.data = data;
$scope.result = data;
})
}
}
submit.php
$post_date = file_get_contents("php://input");
$data = json_decode($post_date);
$to = $data->email;
$from = "John#example.com";
$name = $data->name;
$subject = "Email from AngularJS";
$htmlContent = $data->message;
I have added my code below :
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Dynamic Email AngularJS</title>
</head>
<body ng-app="myApp" ng-cloak>
<div ng-controller="formCtrl">
<pre ng-model="result">
{{result}}
</pre>
<form name="userForm">
<input type="text" class="form-control" ng-model="$parent.name" placeholder="Name Lastname" required>
<input type="text" class="form-control" ng-model="$parent.email" placeholder="me#email.com" required>
<div ng-view></div>
<button ng-click="add()">New Item</button>
<button type="submit" class="btn" ng-click="formsubmit(userForm.$valid)" ng-disabled="userForm.$invalid">Submit </button>
</form>
</div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src="//code.angularjs.org/1.4.3/angular-route.min.js"></script>
<script src="app.js"></script>
</body>
</html>
app.js:
myApp.controller("formCtrl", ['$scope', '$http','$templateRequest','$compile', function($scope, $http, $templateRequest, $compile) {
$scope.lists = [
{
"year":"year I",
"semesters":[
{
"label": "Semester I",
"max": "4",
"courses": [
{"name": "Introductory Accounting I", "type": "populated"},
{"name": "Principles of Economics I", "type": "populated"},
]
},
{
"label": "Semester II",
"max": "4",
"courses": [
{"name": "Accounting Method II", "type": "populated"},
]
}
]
},
{
"year":"year II",
"semesters":[
{
"label": "Semester I",
"max": "4",
"courses": [
{"name": "Introductory Accounting I", "type": "levelII"},
{"name": "Business Finance I", "type": "levelII"}
]
},
{
"label": "Semester II",
"max": "4",
"courses": [
{"name": "Accounting Method II", "type": "levelII"},
{"name": "Management Accounting II", "type": "levelII"},
]
}
]
}
]
$scope.add = function () {
$scope.lists.push(
{
"year":"year III",
"semesters":[
{
"label": "Semester I",
"max": "4",
"courses": [
{"name": "Introductory Accounting I", "type": "levelII"},
{"name": "Business Finance I", "type": "levelII"}
]
},
{
"label": "Semester II",
"max": "4",
"courses": [
{"name": "Accounting Method II", "type": "levelII"},
{"name": "Management Accounting II", "type": "levelII"},
]
}
]
});
}
$scope.url = 'submit.php';
$scope.formsubmit = function(isValid) {
if (isValid) {
$templateRequest('email.html').then(function(html) {
$scope.contentHtml = $compile(html);
});
$http.post($scope.url, {"name": $scope.name, "email": $scope.email, "message": $scope.contentHtml }).
success(function(data, status) {
console.log(data);
$scope.status = status;
$scope.data = data;
$scope.result = data;
})
}else{
alert('Form is not valid');
}
}
}]);
submit.php:
<?php
$post_date = file_get_contents("php://input");
$data = json_decode($post_date);
$to = $data->email;
$from = "Sam#example.com";
$name = $data->name;
$subject = "Dynamic Email";
$htmlContent = $data->message;
// Set content-type header for sending HTML email
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
// Additional headers
$headers .= 'From: '.$from . "\r\n";
if(mail($to,$subject,$htmlContent,$headers)) {
echo "Mail Sent. Thank you " . $name . ", we will contact you shortly.";
} else {
echo 'Sorry there was an error sending your message. Please try again later.';
}
echo "Name : ".$data->name."\n";
echo "Email : ".$data->email."\n";
echo "Hero : ".$data->hero."\n";
echo "Message": $htmlContent;
?>
email.html
<table ng-repeat="list in lists">
<tr>
<td>
<h1>{{list.year}}</h1>
</td>
</tr>
<tr>
<td ng-repeat="semester in list.semesters">
<table>
<tr>
<td>
<h3>{{semester.label}}</h3>
<ul>
<li ng-repeat="course in semester.courses">{{course.name}}</li>
</ul>
</td>
</tr>
</table>
</td>
</tr>
</table>

I had to do the very same thing. But my setup is somewhat different. My Backend is a Firebase.com database. Loaded into my frontend via angularFire, the library for loading stuff into an angular project. I have a mail template in the front-end. In fact, i plan to let users choose their e-mail template from several provided ones. I just fill in the fields, a but like a mail-merge in MS-Office.
On the serverside, i'm using php-mailer (google it!)
In big lines, this is what's happening:
- Create vars like mailTo (all the emails where i have to send mail to) and bind them to the $scope (yeah i know i shouldn't do that but stay with me)
- other stuf from the database records that should be in the mail, i bind to the $scope again.
- and then i do this:
$templateRequest("templates/mail-packs/mail-1.html")
.then(function(emailtemplate) {
var base = angular.element('<div></div>');
base.html(emailtemplate);
$compile(base)($scope);
$timeout(function(){
mail = base.html()
console.log(mail);
constructMail(mail)
}, 300)
})
the base variabel was needed beceause you are not compling to the DOM. You have to trick angular there and start with a blank DOM.
The function constructMail() is a function just doing that, prepping the data to send to the php-mailer.

I have successfully implemented this architecture in my one project. I have created separate service to get email template. I passed URL and $scope object to getTemplate() method and this method will return compiled email template to me.
templateService.js
angular.module('myApp').factory("TemplateService", ['$resource', '$q', '$rootScope', '$templateRequest', '$compile', '$timeout', function ($resource, $q, $rootScope, $templateRequest, $compile, $timeout) {
class TemplateService {
constructor() {
}
/**
* Get the template from url and then compile it with data.
* #param url
* #param $scope
* #returns {*|Promise<T>}
*/
static getTemplate(url, $scope) {
return $templateRequest(url)
.then(function(response){
let template = angular.element('<div></div>');
template.html(response);
//3. Pass the data to email template, in data will be merged in it
$compile(template)($scope);
return $timeout(function(){
return template.html();
}, 300);
})
.catch(function(err){
return $templateRequest('views/templates/404.html');
});
}
}
return TemplateService;
}]);
contact_email.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Email</title>
</head>
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
<table align="center" border="0" cellpadding="0" cellspacing="0" height="100%" width="100%" id="bodyTable" style="background: #f2f2f2;padding:40px 10px;">
<tr>
<td align="center" valign="top" id="bodyCell">
<table border="0" cellpadding="0" cellspacing="0" id="templateContainer" style="background: white;text-align: center;border: 1px solid grey;padding: 20px;box-shadow: 0 0 5px 2px grey;margin:0 auto;">
<tr>
<td align="center" valign="top">
<table border="0" cellpadding="0" cellspacing="0" width="100%" id="templateBody">
<tr>
<td valign="top" class="bodyContent">
Hello {{ contactEmailCtrl.contact.firstName }}
<p compile="contactEmailCtrl.message">
</p>
<p>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
Usage in controller
contact.controller.js
angular.module('myApp').controller('ContactController', ['$scope', 'Global', 'TemplateService', $scope, Global, TemplateService]) {
let vm = this;
vm.sendEmail = function(params) {
//1. Prepare email template, Pass data to email template and compile it
$scope.contactEmailCtrl = {
user: Global.user,
message: $scope.emailCommunication.message || null,
};
TemplateService.getTemplate('views/templates/emails/contact_email.html', $scope).then(function(emailBody) {
console.log('--> | emailBody ', emailBody);
//Todo: Send email
let emailParams = {
tos: 'example#example.com',
subject: 'subject goes here',
emailBody: emailBody
}
// EmailService.sentEmail(emailParams); // Either send by PHP or Nodejs Or Ruby whatever
}).catch(function(err) {
console.log(' err ', err);
});
};
}
This is whole implementation. Hope this will help who wants to maintain clean architecture and separate email html and inject on the fly to send email.

Related

Dom Traversal Complex Table Layout

I a have a webpage with a complex table structure. The entire code is right here --> (index.php)
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
</head>
<body>
<?php
// this turns the json object into an array
$json_string = file_get_contents("info.json");
$json = json_decode($json_string, true);
?>
<div id="scroll_box">
<table border="1" cellpadding="10" id="container">
<tr>
<td>
<table class="organizer">
<?php foreach($json as $key => $value): ?>
<!-- this is what needs to be repeated -->
<tr><td class="index"> <?php echo $key ?> </td></tr>
<thead class="sticky" align="center"><tr><th> <?php echo $value["name"] ?></th></tr></thead>
<tbody>
<tr>
<td>
<table class="spell_container">
<?php
foreach ($value["items"] as $key => $value) {
echo '<tr><td><table class="table-bordered spell_shorthand">'.
'<tr><td>Name</td><td class="name">'.$value["name"].'</td></tr>'.
'<tr><td>Type</td><td class="type">'.$value["type"].'</td></tr>'.
'</table>'.
'</td>'.
'<td class="description">'.$value["description"].'</td>'.
'<td><div class="btn-group"><button class="learn">Learn</button></div></td>'.
'</tr>';
}
?>
</table>
</td>
</tr>
</tbody>
<?php endforeach; ?>
</table>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
$(".learn").on('click', function(){
var the_name = $(this).closest("tr").find("table.spell_shorthand").find("td.name").text();
var the_type = $(this).closest("tr").find("table.spell_shorthand").find("td.type").text();
var the_description = $(this).closest("tr").find("td.description").text();
var the_index = $(this).closest("table.organizer").find("td.index").text();
console.log(the_name);
console.log(the_type);
console.log(the_description);
console.log(the_index);
});
</script>
</body>
</html>
and the JSON data that is being used looks like this --> (info.json)
[
{
"name": "level0",
"items": [
{
"name": "item1",
"type": "type1",
"description": "this is item 1"
},
{
"name": "item2",
"type": "type2",
"description": "this is item 2"
},
{
"name": "item2",
"type": "type2",
"description": "this is item 3"
}
]
},
{
"name": "Level1",
"items": [
{
"name": "item4",
"type": "type4",
"description": "this is item 4"
},
{
"name": "item5",
"type": "type5",
"description": "this is item 5"
}
]
},
{
"name": "Level2",
"items": [
{
"name": "item6",
"type": "type6",
"description": "this is item 6"
}
]
}
]
Now. All of my console.log statements in the js script work perfectly except for the one that deals with "the_index" ... for whatever reason, it is returning all of the instances of index (0, 1, 2) when really it should just be returning the index of the header that is the parent of the button that is clicked.
I encourage you to take these two files and see for yourself what I'm talking about.
Any insight as to why clicking a button under the first index (0) would return (0 1 2) would be appreciated, thank you.
Try running an index on your tables in the loop like so:
<?php
$num_row = 0;
foreach ($value["items"] as $key => $value) {
echo '<tr id="row_'.$num_row.'"><td><table class="table-bordered spell_shorthand">'.
'<tr><td>Name</td><td class="name">'.$value["name"].'</td></tr>'.
'<tr><td>Type</td><td class="type">'.$value["type"].'</td></tr>'.
'</table>'.
'</td>'.
'<td class="description">'.$value["description"].'</td>'.
'<td><div class="btn-group"><button class="learn" data-row-id="#row_'.$num_row.'">Learn</button></div></td>'.
'</tr>';
$num_row = $num_row + 1;
}
?>
You can revise your click event to be something like below using jQuery. This will simplify things quite a bit.
$(".learn").on('click', function(){
var row_selector = $(this).data('row-id');
var the_name = $(row_selector + ' .name').text();
var the_type = $(row_selector + ' .type').text();
var the_description = $(row_selector + ' .description').text();
var the_index = $(row_selector + ' .index').text();
});

AngularJS Json list

I want to show one json to list in my page with AngularJS.But that Json have sub object i try something but not working. I can showing text and id but it's not working lat and lon in posibiton name tag.I don't know how to show that data in my list
var app = angular.module("VarnaApp",[]);
app.service("varnaService",function($http, $q)
{
var deferred = $q.defer();
$http.get('api/station.json').then(function(data)
{
deferred.resolve(data);
});
this.getStations = function ()
{
return deferred.promise;
}
})
.controller ("varnaCtrl",function($scope,varnaService)
{
var promise = varnaService.getStations();
promise.then(function(data)
{
$scope.stations = data.data;
});
})
<!doctype html>
<html lang="en">
<head>
<title>AccioCode AngularJS Tutorial</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-COMPATIBLE" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, user-scalable=no">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="js/app.js"></script>
</head>
<body>
<div class="mainContainer" data-ng-app="VarnaApp">
<h1>Varna Stations</h1>
<div data-ng-controller="varnaCtrl">
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>loc</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="station in stations">
<td>{{station.id}}</td>
<td>{{station.text}}</td>
<td>{{station.loc}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
My Json Is
[
{
"id": 2063,
"text": "test",
"position": {
"lat": 43.357048,
"lon": 27.9815636
}
},
{
"id": 2563,
"text": "test2",
"position": {
"lat": 43.3570175,
"lon": 27.9816666
}
},
{
"id": 2538,
"text": "test3",
"position": {
"lat": 43.3092232,
"lon": 27.97827
}
}
]
I don't quite understand what station.loc should be. If you want to display lat and lon just do it like that:
<tbody>
<tr data-ng-repeat="station in stations">
<td>{{station.id}}</td>
<td>{{station.text}}</td>
<td>{{station.position.lat}}</td>
<td>{{station.position.lon}}</td>
</tr>
</tbody>
The JSON you have is a JSON string. You have to parse it to a JavaScript object first:
.controller ("varnaCtrl",function($scope,varnaService)
{
var promise = varnaService.getStations();
promise.then(function(data)
{
$scope.stations = JSON.parse(data.data);
});
})

Import JSON data for AngularJS Web App

I have been following the Angular tutorials, and I am trying to get my JSON data to appear, yet I know I am doing something wrong, but can't figure out the proper method.
I know that somewhere in my app.js my scope is messed up.
How can I display the Family Name of each product?
Here is the layout I have:
app.js
var eloApp = angular.module('eloMicrosite', []);
eloApp.controller('homeListController', ['$scope', '$http',
function($scope, $http) {
$http.get('/Elo/eloMS.min.json')
.success(function(data) {
$scope.products = data;
});
}]);
eloApp.controller('HomeController', function(){
this.products = $scope.products;
});
HTML
<div ng-controller="HomeController as home">
{{home.products[o]["Family Name"]}}
</div>
JSON Layout
{
"products": [
{
"Family Name": "3201L",
"Type": "IDS",
"Size (inches)": 32,
"Aspect Ratio": "16:9",
"Part Number": "E415988",
"Product Description": "ET3201L-8UWA-0-MT-GY-G",
"Marketing Description": "3201L 32-inch wide LCD Monitor",
"Advance Unit Replacement": "",
"Elo Elite": "",
"Package Quantity": 1,
"Minimum Order Quantity": 1,
"List Price": 1800
},
.
.
.
],
"families": [
{
category: "Category1"
},
{
category: "Category2"
}
],
"accessories": [
{
category: "Category1"
},
{
category: "Category2"
}
]
}
You should add homeListController on your page instead of HomeController, Also need to use this instead of using $scope as you wanted to follow controllerAs syntax, 2nd controller is useless in this scenario, you could remove that from app.js.
Markup
<div ng-controller="homeListController as home">
{{home.products[0]["Family Name"]}}
</div>
Controller
eloApp.controller('homeListController', ['$http',
function($http) {
var home = this;
$http.get('/Elo/eloMS.min.json')
.success(function(data) {
home.products = data.products; //products should mapped here
});
}]);
Demo Plunkr

How to handle item click on list generated from ng-repeat and load next page

I have an html list generated using ng-repeat.
<div ng-repeat="product in store.products">
{{product.name}}
</div>
The data for the list is obtained from a json array in my app.js in this format:
var items = [
{
"name": "Nexus 5",
"size": "4.95 inches",
"camera": "8 megapixels"
},
{
"name": "Nexus 6",
"size": "6.0 inches",
"camera": "13 megapixels"
}
];
I want to click on the list item and go to another page showing the respective details from the same json array. How do I do that? Have been trying to access index from the list and use it to load next page, but am unsuccessful so far. I am new to angular as well as javascript. Any intermediate steps will be very helpful.
Also, notice I am handling click on the list using an anchor tag. Is this the ideal way to do it?
Please see for demo here http://plnkr.co/edit/qVEhc0KgKjklWCmqKJ4L?p=preview
HTML:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="https://code.angularjs.org/1.2.25/angular.js" data-semver="1.2.25"></script>
<script data-require="angular-route#1.2.16" data-semver="1.2.16" src="http://code.angularjs.org/1.2.16/angular-route.js"></script>
<script src="app.js"></script>
</head>
<body >
<div ng-view></div>
</body>
</html>
JS:
var app = angular.module('plunker', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider.when('/main', {
templateUrl: "main.html",
controller: "mainController"
}).when('/detail/:productName', {
templateUrl: "details.html",
controller: "detailsController"
}).otherwise({
redirectTo: "/main"
});
})
.controller("mainController", function($scope, dataService) {
$scope.store = {}; //.products
$scope.store.products = dataService.getProducts();
})
.controller("detailsController", function($scope, $routeParams, dataService) {
$scope.product = dataService.getProductAt($routeParams.productName);
});
angular.module("plunker").service("dataService", function(filterFilter) {
var items = [{
"name": "Nexus 5",
"size": "4.95 inches",
"camera": "8 megapixels"
}, {
"name": "Nexus 6",
"size": "6.0 inches",
"camera": "13 megapixels"
}];
this.getProducts = function() {
return items;
};
this.getProductAt = function(_name) {
this.getProducts();
return filterFilter(items, {
name: _name
})[0];
};
});
(you need details.html and main.htm template as well)

Valid JSON to display data in angularJs

I want to display data(json) in my site using AngularJs . here's what i did :
Create a database in phpmyAdmin .
Create a table with 2 row , subject and body . Should i create an id ?
After doing with PHP and angular , I got JSON like this :
[{
"0":"Soheil","subject":"Soheil",
"1":"Sadeghbayan","body":"Sadeghbayan"}
,{"0":"","subject":"","1":"","body":""}
,{"0":"","subject":"","1":"","body":""}
,{"0":"dasdasd","subject":"dasdasd","1":"qe","body":"qe"}
,{"0":"Hello","subject":"Hello","1":"This is chandler !","body":"This is chandler !"}
,{"0":"","subject":"","1":"","body":""},
{"0":"Something new in website","subject":"Something new in website","1":"oh Awsome !","body":"oh Awsome !"
}]
I think this is invalid JSON because when I replace it with custom JSON that I wrote it work .
Json valid
{
"fruits": [
{
"id": "1",
"name": "Apple"
},
{
"id": "2",
"name": "Orange"
}
]
}
AngularJS
var fruitsApp = angular.module('fruitsApp', []);
fruitsApp.factory('fruitsFactory', function($http) {
return {
getFruitsAsync: function(callback) {
$http.get('fruits.json').success(callback);
}
};
});
fruitsApp.controller('fruitsController', function($scope, fruitsFactory) {
fruitsFactory.getFruitsAsync(function(results) {
console.log('fruitsController async returned value');
$scope.fruits = results.fruits;
});
});
Html
<ul>
<li ng-repeat="fruit in fruits">
{{fruit.subject}} is {{fruit.body}}
</li>
</ul>
php
include('config.php');
$data = json_decode(file_get_contents("php://input"));
$subject = mysql_real_escape_string($data->subject);
$body = mysql_real_escape_string($data->body);
mysql_select_db("angular") or die(mysql_error());
mysql_query("INSERT INTO newstory (subject,body) VALUES ('$subject', '$body')");
Print "Your information has been successfully added to the database.";
$query = "SELECT * FROM newstory";
$result = mysql_query($query);
$arr = array();
while ($row = mysql_fetch_array($result)) {
$subject = $row['subject'];
$body = $row['body'];
$arr[] = $row;
}
echo json_encode($arr);
Any idea ? Thx in advance
Your JSON is a valid. Refer to this for information on JSON and this to check/validate a JSON object.
The data coming back from your $http.get / database data does not have a fruits attribute and you expect that when you set your $scope.fruits (the below snippet is taken from your code):
$scope.fruits = results.fruits;
The structure of the data that is being returned by the $http.get call is different than the format of your sample data.
Here's your $http.get / database data (I shortened it for brevity):
[
{
"0": "Soheil",
"1": "Sadeghbayan",
"subject": "Soheil",
"body": "Sadeghbayan"
},
{
"0": "Hello",
"1": "This is chandler !",
"subject": "Hello",
"body": "This is chandler !"
},
{
"0": "",
"1": "",
"subject": "",
"body": ""
}
]
And here's your sample / mock data:
{
"fruits": [
{
"id": "1",
"name": "Apple"
},
{
"id": "2",
"name": "Orange"
}
]
}
The former is an array of objects with keys: 0, 1, subject and body.
The latter is an object with keys: fruits.
They are both valid JSON objects with different object structures. But, you expect a fruits attribute where there isn't one. Also, your HTML/UI might be expecting the data format to look like what is in your mock data. So check that too.

Categories

Resources