How to modify and convert Google app UI into HTML - api

I try to convert this simple google apps script code below to HTML services code. The code below is written with the deprecated google apps script UI services! Could anyone please help me with HTML services example code in this usecase?
I'm not really sure how to approach it as I haven't been coding for too long.
A little bit of help would be very much appreciated.
Thanks!!
Mireia
function() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication();
app.setHeight(400);
var scriptProps = PropertiesService.getScriptProperties();
var label1 = app.createLabel('XERO Settings').setStyleAttribute('font-weight', 'bold').setStyleAttribute('padding', '5px').setId('label1');
var panel1 = app.createVerticalPanel().setId('panel1');
var grid = app.createGrid(7, 2);
var absPanel = app.createAbsolutePanel();
var handler = app.createServerHandler('saveSettings');
var clientHandler1 = app.createClientHandler();
var clientHandler2 = app.createClientHandler();
var clientHandler3 = app.createClientHandler();
var btnSave = app.createButton('Save Settings', handler);
var lblAppType = app.createLabel('Application Type: ');
var appTypes = {Private:0, Public:1, Partner:2};
var listAppType = app.createListBox().setName('appType').addItem('Private').addItem('Public').addItem('Partner').addChangeHandler(clientHandler1).
addChangeHandler(clientHandler2).addChangeHandler(clientHandler3).setSelectedIndex(appTypes[(scriptProps.getProperty('appType') != null ? scriptProps.getProperty('appType'): 'Private')]);
handler.addCallbackElement(listAppType);
var lblAppName = app.createLabel('Application Name: ');
var txtAppName = app.createTextBox().setName('userAgent').setWidth("350")
.setValue((scriptProps.getProperty('userAgent') != null ? scriptProps.getProperty('userAgent'): ""));
handler.addCallbackElement(txtAppName);
var lblConsumerKey = app.createLabel('Consumer Key: ');
var txtConsumerKey = app.createTextBox().setName('consumerKey').setWidth("350")
.setValue((scriptProps.getProperty('consumerKey') != null ? scriptProps.getProperty('consumerKey'): ""));
handler.addCallbackElement(txtConsumerKey);
var lblConsumerSecret = app.createLabel('Consumer Secret: ');
var txtConsumerSecret = app.createTextBox().setName('consumerSecret').setWidth("350")
.setValue((scriptProps.getProperty('consumerSecret') != null ? scriptProps.getProperty('consumerSecret'): ""));
handler.addCallbackElement(txtConsumerSecret);
var lblcallBack = app.createLabel('Callback URL:');
var txtcallBack = app.createTextBox().setName('callBack').setWidth("350")
.setValue((scriptProps.getProperty('callbackURL') != null ? scriptProps.getProperty('callbackURL'): ""));
handler.addCallbackElement(txtcallBack);
var lblRSA = app.createLabel('RSA Private Key:');
var txtareaRSA = app.createTextArea().setName('RSA').setWidth("350").setHeight("150")
.setValue((scriptProps.getProperty('rsaKey') != null ? scriptProps.getProperty('rsaKey'): ""));
if (scriptProps.getProperty('appType') == "Private" || scriptProps.getProperty('appType') == null)
txtcallBack.setEnabled(false);
else if (scriptProps.getProperty('appType') == "Public")
txtareaRSA.setEnabled(false);
handler.addCallbackElement(txtareaRSA);
clientHandler1.validateMatches(listAppType, 'Private').forTargets(txtcallBack).setEnabled(false).forTargets(txtareaRSA).setEnabled(true);
clientHandler2.validateMatches(listAppType, 'Public').forTargets(txtcallBack).setEnabled(true).forTargets(txtareaRSA).setEnabled(false);
clientHandler3.validateMatches(listAppType, 'Partner').forTargets(txtcallBack).setEnabled(true).forTargets(txtareaRSA).setEnabled(true);
grid.setBorderWidth(0);
grid.setWidget(0, 0, lblAppType);
grid.setWidget(0, 1, listAppType);
grid.setWidget(1, 0, lblAppName);
grid.setWidget(1, 1, txtAppName);
grid.setWidget(2, 0, lblConsumerKey);
grid.setWidget(2, 1, txtConsumerKey);
grid.setWidget(3, 0, lblConsumerSecret);
grid.setWidget(3, 1, txtConsumerSecret);
grid.setWidget(4, 0, lblcallBack);
grid.setWidget(4, 1, txtcallBack);
grid.setWidget(5, 0, lblRSA);
grid.setWidget(5, 1, txtareaRSA);
grid.setWidget(6, 1, btnSave);
panel1.add(grid).setStyleAttributes(subPanelCSS);
app.add(label1);
app.add(panel1);
ss.show(app);
}

Description
Unfortunately there is no converter. Your dialog is relatively simple and I think I have captured everything of interest. I expect you to handle the property services.
In the dialog I changed the appType from Public to Private to show that the changed values are sent to the server for property service as shown in the execution log.
I inadvertently put include in Code.gs because I normally put CSS in one file, HTML another and js in a third. I didn't do that in this instance.
HTML_Test
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
#label1 { font-weight: bold; }
.textBox { width: 350px; }
.table { display: table; }
.table-row { display: table-row; }
.table-cell { display: table-cell; }
</style>
</head>
<body>
<p id="label1">XERO Settings</p>
<div class="panel1">
<div class="table">
<div class="table-row">
<div class="table-cell">Application Type:</div>
<div class="table-cell">
<select class="textBox" id="appType" onchange="appTypeOnChange()">
<option>Private</option>
<option>Public</option>
<option>Partner</option>
</select>
</div>
</div>
<div class="table-row">
<div class="table-cell">Application Name:</div>
<div class="table-cell">
<input class="textBox" id="userAgent" value=<?= userAgent?>>
</div>
</div>
<div class="table-row">
<div class="table-cell">Consumer Key:</div>
<div class="table-cell">
<input class="textBox" id="consumerKey" value=<?= consumerKey ?>>
</div>
</div>
<div class="table-row">
<div class="table-cell">Consumer Secret:</div>
<div class="table-cell">
<input class="textBox" id="consumerSecret" value=<?= consumerSecret ?>>
</div>
</div>
<div class="table-row">
<div class="table-cell">Callback URL:</div>
<div class="table-cell">
<input class="textBox" id="callBack" value=<?= callBack ?>>
</div>
</div>
<div class="table-row">
<div class="table-cell">RSA Private Key:</div>
<div class="table-cell">
<input class="textBox" id="rsaKey" value=<?= rsaKey ?>>
</div>
</div>
</div>
</div>
<input class="btnSave" type="button" value="Save Settings" onclick="saveSettings()">
<script>
function appTypeOnChange() {
let value = document.getElementById("appType").value;
if( value == "Private" ) {
document.getElementById("callBack").disabled = true;
document.getElementById("rsaKey").disabled = false;
}
else if( appType == "Public" ) {
document.getElementById("callBack").disabled = false;
document.getElementById("rsaKey").disabled = true;
}
else {
document.getElementById("callBack").disabled = false;
document.getElementById("rsaKey").disabled = false;
}
}
function saveSettings() {
let props = {};
props.appType = document.getElementById("appType").value;
props.userAgent = document.getElementById("userAgent").value;
props.consumerKey = document.getElementById("consumerKey").value;
props.consumerSecret = document.getElementById("consumerSecret").value;
props.callBack = document.getElementById("callBack").value;
props.rsaKey = document.getElementById("rsaKey").value;
props = JSON.stringify(props);
google.script.run.setProperties(props);
}
(function () {
let appType = <?= appType ?>;
document.getElementById("appType").value=appType;
if( appType == "Private" ) {
document.getElementById("callBack").disabled = true;
}
else if( appType == "Public" ) {
document.getElementById("rsaKey").disabled = true;
}
}());
</script>
</body>
</html>
Dialog
Code.gs
function showTest() {
try {
let html = HtmlService.createTemplateFromFile('HTML_Test');
html.appType = "Public";
html.userAgent = "John Smith";
html.consumerKey = "12345678";
html.consumerSecret = "My Secret";
html.callBack = "www.goggle.com";
html.rsaKey = "abcdefg";
html = html.evaluate();
SpreadsheetApp.getUi().showModalDialog(html,"Show Test");
}
catch(err) {
SpreadsheetApp.getUi().alert(err);
}
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
};
function setProperties(props) {
Logger.log(props);
}
Execution log
Head setProperties Unknown May 11, 2022, 8:27:15 AM 0.57 s
Completed
Cloud logs
May 11, 2022, 8:27:16 AM Info {"appType":"Private","userAgent":"John Smith","consumerKey":"12345678","consumerSecret":"My Secret","callBack":"www.goggle.com","rsaKey":"abcdefg"}
Reference
HTML Service Templated HTML

Related

Select checkbox and shows its related objects in Vue.js

In my Vue.js project, I have two separate components are Country and States. I have merged them in one page. So now if I select one country it will display related states. How to do this?
<template>
<div>
<div style=margin-left:355px><country-index></country-index></div>
<div style=margin-left:710px><state-index></state-index></div>
</div>
</template>
<script>
import { ROAST_CONFIG } from '../../../config/config.js';
import CountryIndex from './components/country/Index';
import StateIndex from './components/state/Index';
import { listen } from '../../../util/history.js';
import axios from 'axios'
let baseUrl = ROAST_CONFIG.API_URL;
export default {
name: 'LocationsView',
layout: 'admin/layouts/default/defaultLayout',
middleware: 'auth',
components: {
'country-index' : CountryIndex,
'state-index' : StateIndex,
},
data() {
return { currentComponent:'','countryId':''}
},
methods: {
updateCurrentComponent(){
console.log(this.$route.name);
let vm = this;
let route = vm.$route;
if(this.$route.name == "Locations"){
this.currentComponent = "country-index";
}
}
},
mounted() {
let vm = this;
let route = this.$route;
window.addEventListener('popstate',this.updateCurrentComponent);
},
created() {
this.updateCurrentComponent();
}
}
Country Component
<template>
<div style="display:flex;height:100%">
<d-dotloader v-if="componentLoading" />
<div id="parent" class="list-manager" v-if="!componentLoading">
<div class="list-header">
<div class="bulk-action" :class="{'hide': showTop}" >
<div class="pull-left">
Countries
</div>
<!-- /pull-left -->
<div class="pull-right">
<d-button #click.native = "addCountry();"><i class="icon icon-sm"></i><span>New</span></i></d-button>
</div>
</div>
<!-- /bulk-action -->
<div class="bulk-action" :style ="{display:(showTop)?'block!important':'none!important'}" >
<div class="btn-toolbar">
<d-check field-class="check" v-model="selectAll" wrapper-class="field-check field-check-inline" label-position="right" label="" value="sel" #click.native = "toggleSelectAll();"/>
<d-button :is-loading="isLoading" #click.native = "deleteCountry();">Delete<i class="icon icon-sm" name="trash-2"></i></d-button>
<!-- <div class="pull-right mt5"><div class="green-bubble"></div>{{SelectedItems}}</div> -->
<d-button #click.native = "closeBulkToolBar();">close<i class="icon icon-sm" name="x"></i></d-button>
</div>
</div>
<!-- /bulk-action -->
</div>
<d-dotloader v-if="subListComponentLoading" />
<d-list-items :data="fetchData" #rowClick="changeCountryView" ref="itemsTable">
<d-list-cell column-class="list-item-check" :column-styles="{width: '40px'}" type="selectAll">
<template scope="row">
<div class="field-check field-check-inline" #click.stop="toggleSelect(row.rowIndex)" >
<input type="checkbox" class="check" :id="row.id" :value="row.id" :checked="row.selectAll">
<label></label>
</div>
<d-button #click.native = "editCountry(row.id);">Edit</d-button>
</template>
</d-list-cell>
<d-list-cell column-class="list-item-content">
<template scope="row">
<div class="list-item-content">
<div class="list-item-title">
<div class="pull-right">{{row.ISO_Code}}</div>
<div title="" class="pull-left">{{row.country_name}}</div>
</div>
<div class="list-item-meta">
<div class="pull-right">{{row.Default_Currency}} | {{row.Call_prefix}} </div>
<div class="pull-left">{{row.Zone}}</div>
</div>
<span class="list-item-status enabled"></span>
</div>
</template>
</d-list-cell >
</d-list-items>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { ROAST_CONFIG } from '../../../../../config/config.js';
var baseUrl = ROAST_CONFIG.API_URL;
export default {
data () {
return {
SelectedItems:"",
isLoading:false,
show:true,
searchBy: '',
activeSearch: '',
showTop: false,
selectAll : false,
componentLoading:true,
subListComponentLoading:false,
showModal: false,
form :{
country_name: '',
isCountryEnabled: true,
}
}
},
methods: {
async fetchData ({search, page, filter, sort,rows}) {
let resData;
let vm = this;
axios.defaults.headers.common['Authorization'] = "Bearer "+localStorage.getItem('token');
const res = await axios.post(baseUrl+'/country/fetch',{search, page, filter, sort,rows})
.then((response) => {
if( (typeof(response) != 'undefined') && (typeof(response.data) != 'undefined') && (typeof(response.data.fetch) != 'undefined')){
return response.data.fetch;
}
});
return res;
},
toggleSelect(rowId){
if(typeof(this.$refs.itemsTable.rows[rowId]) != 'undefined'){
this.$refs.itemsTable.rows[rowId].selectAll = !this.$refs.itemsTable.rows[rowId].selectAll;
let data = this.$refs.itemsTable.rows;
let status = false;
let selectAllStatus = true;
let items = 0;
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')&&(data[i].selectAll)){
items++;
this.SelectedItems = items +" Selected Items";
status = true;
}
if((typeof(data[i])!= 'undefined')&&(!data[i].selectAll)){
selectAllStatus = false;
}
this.showTop = status
}
}
},
toggleSelectAll(){
this.selectAll = !this.selectAll;
let items = 0;
let data = this.$refs.itemsTable.rows;
let status = false;
let rowId = '1'
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')){
items++;
this.SelectedItems = items +" Selected Items";
status = this.selectAll;
data[i].selectAll = status;
}
}
this.showTop = status
},
closeBulkToolBar(){
this.SelectedItems = "";
this.showTop = false;
},
}
}
State Component
<template>
<div style="display:flex;height:100%">
<d-dotloader v-if="componentLoading" />
<div id="parent" class="list-manager" v-if="!componentLoading">
<div class="list-header">
<div class="bulk-action" :class="{'hide': showTop}" >
<div class="pull-left">
States
</div>
<!-- /pull-left -->
<div class="pull-right">
<d-button #click.native = "addState();"><i class="icon icon-sm"></i><span>New</span></i></d-button>
</div>
</div>
<!-- /bulk-action -->
<div class="bulk-action" :style ="{display:(showTop)?'block!important':'none!important'}" >
<div class="btn-toolbar">
<d-check field-class="check" v-model="selectAll" wrapper-class="field-check field-check-inline" label-position="right" label="" value="sel" #click.native = "toggleSelectAll();"/>
<d-button :is-loading="isLoading" #click.native = "deleteState();">Delete<i class="icon icon-sm" name="trash-2"></i></d-button>
<!-- <div class="pull-right mt5"><div class="green-bubble"></div>{{SelectedItems}}</div> -->
<d-button #click.native = "closeBulkToolBar();">close<i class="icon icon-sm" name="x"></i></d-button>
</div>
</div>
<!-- /bulk-action -->
</div>
<d-dotloader v-if="subListComponentLoading" />
<d-list-items :data="fetchData" #rowClick="changeStateView" ref="itemsTable">
<d-list-cell column-class="list-item-check" :column-styles="{width: '40px'}" type="selectAll">
<template scope="row">
<div class="field-check field-check-inline" #click.stop="toggleSelect(row.rowIndex)" >
<input type="checkbox" class="check" :id="row.id" :value="row.id" :checked="row.selectAll">
<label></label>
</div>
<d-button #click.native = "editState(row.id);">Edit</d-button>
</template>
</d-list-cell>
<d-list-cell column-class="list-item-content">
<template scope="row">
<div class="list-item-content">
<div class="list-item-title">
<div class="pull-right">{{row.ISO_Code}}</div>
<div title="" class="pull-left">{{row.state_name}}</div>
</div>
<div class="list-item-meta">
<div class="pull-left">{{row.country_name}} </div>
<div class="pull-right">{{row.Zone}}</div>
</div>
<span class="list-item-status enabled"></span>
</div>
</template>
</d-list-cell >
</d-list-items>
</div>
<state-add></state-add>
<state-edit></state-edit>
</div>
</template>
<script>
import axios from 'axios'
import { ROAST_CONFIG } from '../../../../../config/config.js';
var baseUrl = ROAST_CONFIG.API_URL;
export default {
data () {
return {
SelectedItems:"",
isLoading:false,
show:true,
searchBy: '',
activeSearch: '',
showTop: false,
selectAll : false,
componentLoading:true,
subListComponentLoading:false,
showModal: false,
form :{
country_name: '',
isCountryEnabled: true,
}
}
},
methods: {
async fetchData ({search, page, filter, sort,rows}) {
let resData;
let vm = this;
axios.defaults.headers.common['Authorization'] = "Bearer "+localStorage.getItem('token');
const res = await axios.post(baseUrl+'/state/fetch',{search, page, filter, sort,rows})
.then((response) => {
if( (typeof(response) != 'undefined') && (typeof(response.data) != 'undefined') && (typeof(response.data.fetch) != 'undefined')){
return response.data.fetch;
}
});
return res;
},
changeStateView(row){
if(typeof(this.$children[7]) != 'undefined'){
this.$parent.stateId = row.id;
this.viewComponent = "state-main";
this.$children[7].readState(this.$parent.stateId);
this.$router.push({name:"StatesView", params: {id:row.id}});
}
},
toggleSelect(rowId){
if(typeof(this.$refs.itemsTable.rows[rowId]) != 'undefined'){
this.$refs.itemsTable.rows[rowId].selectAll = !this.$refs.itemsTable.rows[rowId].selectAll;
let data = this.$refs.itemsTable.rows;
let status = false;
let selectAllStatus = true;
let items = 0;
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')&&(data[i].selectAll)){
items++;
this.SelectedItems = items +" Selected Items";
status = true;
}
if((typeof(data[i])!= 'undefined')&&(!data[i].selectAll)){
selectAllStatus = false;
}
this.showTop = status
}
}
},
toggleSelectAll(){
this.selectAll = !this.selectAll;
let items = 0;
let data = this.$refs.itemsTable.rows;
let status = false;
let rowId = '1'
for(var i=0;i <= data.length;i++){
if((typeof(data[i])!= 'undefined')){
items++;
this.SelectedItems = items +" Selected Items";
status = this.selectAll;
data[i].selectAll = status;
}
}
this.showTop = status
},
closeBulkToolBar(){
this.SelectedItems = "";
this.showTop = false;
},
}
}
Without your component codes it will be difficult to accuratly answer but I can give a try. To communicate between your two components that don't have parent/child relationship you can use an EventBus. You have several choices on how to set up your EventBus; you can pass your event through your Vue root instance using $root, or you can create a dedicated Vue component like in this example.
Considering that you already have binded the event countrySelected($event) on each of your country checkbox, you could achieve to display the related states using something like this:
./components/country/Index
The CountryIndex trigger an event while a country is selected
methods: {
countrySelected(event) {
let currentTarget = event.currentTarget
this.$root.$emit("display-states",currentTarget.countryId);
}
}
./components/state/Index
The stateIndex component listen to the event and display the related state
mounted() {
/**
* Event listener
*/
this.$root.$on("display-states", countryId => {
this.diplayStates(countryId);
});
},
methods: {
displayStates(countryId) {
//your method selecting the states to be diplayed
}

MVC displaying and updating picture from byte

I am trying to add an editing function to a DB record that a user submitted. The thing is, that there is a picture (as byte) in the mix. The picture has previously been cropped (mainly for styling reasons) and of course, a user would need to have the option to a) keep the existing picture or b) select and crop a new picture. The following code works fine if a user submits a new picture, but in case there is no new picture, it would override the existing one instead of keeping the one the user previously uploaded.
Here's my controller:
// POST: EditErrand
public ActionResult UpdateErrand([Bind(Exclude = "Picture")]EditErrandsViewModel model)
{
string newPic = Request.Form["editErrandCroppedPicture"];
byte[] imageBytes = Convert.FromBase64String(newPic);
var userId = User.Identity.GetUserId();
var errand = new EditErrandsViewModel
{
ID = model.ID,
UserID = User.Identity.GetUserId(),
FirstName = UserManager.FindById(userId).FirstName,
Email = UserManager.FindById(userId).Email,
Phone = UserManager.FindById(userId).PhoneNumber,
Hometown = UserManager.FindById(userId).Hometown,
Rating = model.Rating,
Category = model.Category,
SubCategory = model.SubCategory,
Title = model.Title,
Description = model.Description,
Location = model.Location,
ASAP = model.ASAP,
StartDateTime = model.StartDateTime,
DurationInHours = model.DurationInHours,
EndDateTime = model.EndDateTime,
DateTimePosted = DateTime.UtcNow.ToUniversalTime(),
Currency = model.Currency,
Offering = model.Offering,
Price = model.Price,
errandTax = model.errandTax,
PaymentMethod = model.PaymentMethod,
LatitudePosted = model.LatitudePosted,
LongitudePosted = model.LongitudePosted,
LocationPosted = model.LocationPosted,
UserActivityLatitude = model.LatitudePosted,
UserActivityLongitude = model.LongitudePosted,
UserActivityLocation = model.LocationPosted,
Published = false
};
if (imageBytes.Length > 2)
{
errand.Picture = imageBytes;
}
DB.Entry(errand).State = EntityState.Modified;
DB.SaveChanges();
var Success = new UserActivities
{
ActivityName = "EditErrand_Success",
UserID = User.Identity.GetUserId(),
ActivityTimeStamp = DateTime.Now.ToUniversalTime(),
ActivityLatitude = model.UserActivityLatitude,
ActivityLongitude = model.UserActivityLongitude,
ActivityLocation = model.UserActivityLocation
};
DB.UserActivityList.Add(Success);
DB.SaveChanges();
return RedirectToAction("errandPreview");
}
The controller has the following statement in there because if a user does not upload a file, it would still write 0x to the DB.
if (imageBytes.Length > 2)
{
errand.Picture = imageBytes;
}
For the sake of completeness I have added the relevant part of the view as well, so you get an idea on how cropping (using JCrop) is done:
<div id="editErrandPictureDisplay" class="errandomDisplay col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-4 col-md-7 col-lg-offset-5 col-lg-6">
<img id="editErrandPicture" class="editErrandPicture" src="#Url.Action("errandPicture", "errandom")" />
</div>
<div id="editErrandPictureArea" class="manageArea row">
#Html.LabelFor(m => m.Picture, new { #id = "editErrandPictureLabel", #class = "manageLabel col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-1 col-md-3 col-lg-offset-1 col-lg-4" })
<a id="editErrandPictureSelectionButton" class="manageField col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-0 col-md-7 col-lg-offset-0 col-lg-6" href="#">
select a file...
</a>
#Html.TextBoxFor(m => m.Picture, new { #id = "editErrandPictureField", #class = "manageField col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-0 col-md-7 col-lg-offset-0 col-lg-6", #type = "file", #style = "display: none" })
</div>
<hr />
<script>
jQuery("#editErrandPictureSelectionButton").click(function () {
$("#editErrandPictureField").click();
$("#editErrandCroppingArea").show();
});
</script>
<script>
$("#editErrandPictureField").change(function () {
var fullFileName = $("#editErrandPictureField").val()
$("#editErrandPictureSelectionButton").html(fullFileName.substr(fullFileName.lastIndexOf('\\') + 1));
});
</script>
<div id="editErrandCroppingArea" class="manageArea row" style="display: none">
<img id="editErrandOriginal" class="editErrandImage" src="" alt="" style="display: none" />
<canvas id="editErrandCropped" class="editErrandImage" height="5" width="5"></canvas>
<input id="editErrandButtonCrop" class="manageButton col-xs-offset-1 col-xs-10 col-sm-offset-1 col-sm-10 col-md-offset-1 col-md-10 col-lg-offset-1 col-lg-10" type="button" value="Crop" />
<input id="editErrandCropX" class="editErrandData" name="editErrandCropX" type="hidden" />
<input id="editErrandCropY" class="editErrandData" name="editErrandCropY" type="hidden" />
<input id="editErrandCropW" class="editErrandData" name="editErrandCropW" type="hidden" />
<input id="editErrandCropH" class="editErrandData" name="editErrandCropH" type="hidden" />
<input id="editErrandCroppedPicture" class="editErrandData" name="editErrandCroppedPicture" type="hidden" />
</div>
<script type="text/javascript">
$(function () {
if ($('#editErrandCroppingArea').width() > 500) {
$('#editErrandPictureField').change(function () {
$('#editErrandOriginal').hide();
var reader = new FileReader();
reader.onload = function (e) {
$('#editErrandOriginal').show();
$('#editErrandOriginal').attr("src", e.target.result);
$('#editErrandOriginal').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates,
aspectRatio: 1,
boxWidth: 450,
addClass: 'editErrandCropping'
});
}
reader.readAsDataURL($(this)[0].files[0]);
});
}
else {
$('#editErrandPictureField').change(function () {
$('#editErrandOriginal').hide();
var reader = new FileReader();
reader.onload = function (e) {
$('#editErrandOriginal').show();
$('#editErrandOriginal').attr("src", e.target.result);
$('#editErrandOriginal').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates,
aspectRatio: 1,
boxWidth: 250,
addClass: 'editErrandCropping'
});
}
reader.readAsDataURL($(this)[0].files[0]);
});
}
$('#editErrandButtonCrop').click(function () {
var x1 = $('#editErrandCropX').val();
var y1 = $('#editErrandCropY').val();
var height = $('#editErrandCropH').val();
var width = $('#editErrandCropW').val();
var canvas = $("#editErrandCropped")[0];
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function () {
canvas.height = height;
canvas.width = width;
context.drawImage(img, x1, y1, width, height, 0, 0, width, height);
var image = canvas.toDataURL().replace(/^data:image\/[a-z]+;base64,/, "");
$('#editErrandCroppedPicture').val(image);
//$('#editErrandButtonUpload').show();
$('#editErrandCropped').hide();
$('#editErrandButtonCrop').hide();
};
img.src = $('#editErrandOriginal').attr("src");
});
});
function SetCoordinates(c) {
$('#editErrandCropX').val(c.x);
$('#editErrandCropY').val(c.y);
$('#editErrandCropW').val(c.w);
$('#editErrandCropH').val(c.h);
$('#editErrandButtonCrop').show();
};
</script>
So ultimately my question is:
How can I update the picture if a user selects a new one (which works fine) AND make sure the previously uploaded picture is not overridden if a user does not select a new picture? Right now, all values would be updated except for the picture (unless a new picture is selected and cropped).
Now after adding a View Model, I get the following error:
The entity type EditErrandViewModel is not part of the model for the current context.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details:
System.InvalidOperationException: The entity type EditErrandViewModel is not part of the model for the current context.
Source Error:
Line 348: errand.Picture = imageBytes;
Line 349: }
Line 350: DB.Entry(errand).State = EntityState.Modified;
Line 351: DB.SaveChanges();
Line 352: var Success = new UserActivities

Mvc Fileupload controler not save in document

How do i save a image in folder in mvc 4.
Here is the code:
<form method="post" class="form-horizontal" name="NewLabelform" enctype="multipart/form-data">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Add New Ticket</h4>
</div>
<div class="modal-body">
<p>
<span>Type:</span>
<select class="form-control" id="addtype">
<option value="1">Technical Issue</option>
<option value="2">Bug</option>
<option value="3">Feature Request</option>
<option value="4">Sales Question</option>
<option value="5">How To</option>
</select>
<span id="errortype" style="color: Red;"></span>
</p>
<p>
<span>Title:</span>
<input type="text" class="form-control" id="addTitle" />
<span id="errorTitle" style="color: Red;"></span>
</p>
<p>
<span>description:</span>
<textarea rows="4" cols="50" class="form-control" id="addDesc"></textarea>
<span id="errorDesc" style="color: Red;"></span>
</p>
<p>
<span>Importancy:</span>
<select class="form-control" id="addimportancy">
<option value="1">High</option>
<option value="2">Medium</option>
<option value="3">Low</option>
</select>
<span id="errorimportancy" style="color: Red;"></span>
</p>
<p>
<span>Attached Documents:</span>
<input type="file" name="fileuploader" class="form-control" id="fileuploader" />
<span id="errorAttach" style="color: Red;"></span>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="CreateLabeData()">Create</button>
</div>
</form>
Here is the Ajax Method:
<script>
var $al = jQuery.noConflict();
function CreateLabeData() {
debugger
var errortype = document.getElementById('errortype');
var addtype = document.getElementById('addtype');
if (addtype.length == "0") {
errortype.innerHTML = "Type is required.";
addtype.focus();
return false;
}
else {
errortype.innerHTML = "";
}
var errorTitle = document.getElementById('errorTitle');
var addTitle = document.getElementById('addTitle');
if (addTitle.value == '') {
errorTitle.innerHTML = "Title is required.";
addTitle.focus();
return false;
}
else {
errorTitle.innerHTML = "";
}
var errorDesc = document.getElementById('errorDesc');
var addDesc = document.getElementById('addDesc');
if (addDesc.value == '') {
errorDesc.innerHTML = "Description is required.";
addDesc.focus();
return false;
}
else {
errorDesc.innerHTML = "";
}
var errorimportancy = document.getElementById('errorimportancy');
var addimportancy = document.getElementById('addimportancy');
if (addimportancy.length == "0") {
errorimportancy.innerHTML = "Importancy is required.";
addimportancy.focus();
return false;
}
else {
errorimportancy.innerHTML = "";
}
//var foldername = document.getElementById("fname").value;
var readdtype = document.getElementById('addtype').value;
var readdTitle = document.getElementById('addTitle').value;
var readdDesc = document.getElementById('addDesc').value;
var readdimportancy = document.getElementById('addimportancy').value;
//var fname = document.querySelector('input[type=file]').files[0].name;
//var doc = $al("#fileuploader").val();
//var filename = doc.replace(/^.*[\\\/]/, '');
//var formData = new FormData();
//var totalFiles = document.getElementById("fileuploader").files.length;
//for (var i = 0; i < totalFiles; i++) {
// var file = document.getElementById("fileuploader").files[i];
// formData.append("fileuploader", file);
//}
//formData.append("fileuploader", file);
$.ajax(
{
//url: "/Ticket/InsertTicket/",
url: '#Url.Content("~/TicketTemplate/InsertTicket")',
type: "POST",
cache: false,
async: true,
datatype: "json",
contentType: 'application/json; charset=utf-8',
//data: JSON.stringify({ 'Addtype': readdtype, 'AddTitle': readdTitle, 'AddDesc': readdDesc, 'Addimportancy': readdimportancy, 'FileName': filename,' FormData': formData }),
data: JSON.stringify({ 'Addtype': readdtype, 'AddTitle': readdTitle, 'AddDesc': readdDesc, 'Addimportancy': readdimportancy }),
success: function (result) {
debugger;
if (result.isSuccess) {
window.location.reload(true);
}
else {
alert('!');
}
},
error: function (result) {
debugger;
alert('');
}
});
}
Here is the controller:
public ActionResult InsertTicket(HttpPostedFileBase FileName, string Addtype, string AddTitle, string AddDesc, string Addimportancy, string FormData)
//public ActionResult InsertTicket( string Addtype, string AddTitle, string AddDesc, string Addimportancy)
{
string isSuccess = "0";
AppTicket models;
AppTicket model = new AppTicket();
model.Type = Convert.ToInt32(Addtype);
model.Title = Convert.ToString(AddTitle);
model.Description = Convert.ToString(AddDesc);
model.Importancy = Convert.ToInt32(Addimportancy);
//obj.Title = Convert.ToString(AddTitle);
int CompanyId = 1;
int status = 1;
//if (FileName != null)
//{
// string saveto = string.Empty;
// // var File = FileName;
// //saveto = Path.Combine(Server.MapPath("~/Content/Areas/Ticket/Content"), FileName);
// // File.SaveAs(saveto);
//}
//var file = Request.Files;
////string saveto = string.Empty;
//string name = string.Empty;
//if (Request.Files.Count > 0)
//{
// var File = Request.Files[0];
// Random rnd = new Random();
// name = rnd.Next(111, 9999).ToString() + "_" + System.IO.Path.GetFileName(File.FileName);
// saveto = Path.Combine(Server.MapPath("~/Content/Areas/Ticket/Content"), name);
// File.SaveAs(saveto);
// // Session["File"] = name;
// Session["File"] = saveto;
//}
Int64? res = _apiTicket.Posts(model.Title, (model.Type), model.Description, (model.Importancy), "", (UserId), CompanyId, false, status);
if (res > 0)
{
isSuccess = "1";
}
return Json(isSuccess, JsonRequestBehavior.AllowGet);
}
How do i save uploaded file in folder??
I have tried a lot but this is not working for me...any suggestion??
In a model popup i need to show the form having all these component.
When click on save it need to save on the folder and name in db.
But it is not working??
So any one can try or give me some solutions??

Polymer. It is possible to render element in {{}}?

In json i have metadata of field's type of control (textbox, textarea, combobox, email, date, address etc).
{
"Metadata":
"Fields":
[
{
"Fieldname": "id",
"Title": "Uniq id",
"ClientValueType":"int",
"ClientControltType":"textbox",
"ClientInputWidth":"9"
},
{
"Fieldname": "name_full",
"Title": "org full name",
"ClientValueType":"string",
"ClientControlType":"textarea",
"ClientInputWidth":"100"
},
{
"Fieldname": "name_full",
"Title": "org full name",
"ClientValueType":"string",
"ClientControlType":"textarea",
"ClientInputWidth":"100"
}
]
},"Data":[ {id:1, name_full:"org1"}, {id:2, name_full:"org2"}]
}
Let's this controls in different files for each edit type: textbox.html, textarea.html, combobox.html etc.
Textbox.html for example
<polymer-element name="text-box" noscript>
<template>
here is textbox
</template>
</polymer-element>
I need to dynamically import these elements to render dynamic edit form based on field.ClientControlType value
<polymer-element name="rawc-detail" attributes="data">
<template>
<div class="panel panel-default">
<div class="panel-body">
<form class="form-horizontal" role="form">
<template id="fields" repeat="{{val in fields}}">
<div class="form-group">
<label for="val.Name" class="col-sm-2 control-label">{{val.Title}}</label>
<div class="col-sm-10">{{val.element}}</div>
</div>
</template>
</form>
</div>
</div>
<style>
</style>
</template>
<script>
Polymer({
data:{},
ready: function() {
this.fields = [];
},
dataChanged: function(oldValue, newValue) {
this.bindNewData();
},
bindNewData: function() {
console.log(this.data);
var t = document.querySelector('rawc-detail::shadow #fields');
if (t)
{
var model = {
fields: []
};
for (var i=0; i<this.data.Metadata.Fields.length; i++)
{
var field = this.data.Metadata.Fields[i];
//console.log(field);
if (field.ClientControlType == "textbox")
{
var link = document.createElement('link');
link.href='http://localhost/testdatafile?shema=polymer_parts&name=textbox.html';
this.parentNode.appendChild(link);
//this.ownerDocument
// Polymer.import(['http://localhost/testdatafile?shema=polymer_parts&name=textbox.html'], function() {
var name = 'el-'+field.Fieldname;
console.log(name);
var textbox = document.createElement(name, 'rawc-textbox');
console.log(textbox);
//t.appendChild(textbox);
field.element = textbox;
model.fields.push(field);
// var tt = document.querySelector('rawc-detail::shadow '+name);
// console.log('tt=', tt);
// tt.description = 'a dynamic import';
// });
}
// console.log(field);
}
t.model = model;
}
}
});
is this possible?
detail.html
<polymer-element name="rawc-detail" attributes="data">
<template>
<apply-author-styles></apply-author-styles>
<h3 title="{{data.Metadata.DescOne}}" class="text-center">{{data.Metadata.TitleOne}}</h3>
<div class="panel panel-default">
<div class="panel-body">
<form class="form-horizontal" role="form">
<div id="forminner">
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-primary" on-tap="ClickOk()">Ок</button>
<button type="button" class="btn btn-primary" on-tap="ClickCancel()">Отмена</button>
</div>
</div>
</form>
</div>
</div>
<style>
</style>
</template>
<script>
Polymer({
data:{},
ready: function() {
this.fields = [];
},
dataChanged: function(oldValue, newValue) {
this.bindNewData();
},
inarray: function(val, arr) {
for(var i=0; i<arr.length; i++)
if (arr[i] == val)
return true;
return false;
},
bindNewData: function() {
var t = document.querySelector('rawc-detail::shadow #forminner');
var elementUrls = [];
for (var i=0; i<this.data.Metadata.Fields.length; i++)
{
var field = this.data.Metadata.Fields[i];
var el = null;
var name = 'el-'+field.Fieldname;
if (field.ClientControlType === "textbox")
{
el = document.createElement('rawc-textbox');
el.id = name;
el.data = this.data.Content[0].Data[field.Fieldname];
url = 'http://localhost/testdatafile?shema=polymer_parts&name=textbox.html';
if (!this.inarray(url, elementUrls))
elementUrls.push(url);
}
var div=document.createElement('div');
div.className="form-group";
var label = document.createElement('label');
label.id = name;
label.className = "col-sm-2 control-label";
label.for = field.Name;
label.innerHTML = field.Title;
div.appendChild(label);
if (el != null)
div.appendChild(el);
t.appendChild(div);
}
for(var i=0; i<elementUrls.length; i++)
Polymer.import([elementUrls[i]]);
}
});
</script>
</polymer-element>
textbox.html
<polymer-element name="rawc-textbox" attributes="data">
<template id="textbox">
<input type="text" value="{{data}}">
<button on-click="{{clickme}}">go</button>
</template>
<script>
Polymer(
{
clickme:function(e,p,o){
console.log(this.data);
}
});
</script>
</polymer-element>

localStorage and updateView + windows 8

I have some items and I mark them as favorite by pressing a button, here is the code:
function AddToFavorites() {
//called when a shop is added as as a favorite one.
//first we check if already is favorite
var favoritesArray = getStoreArray();
var alreadyExists = exists();
if (!alreadyExists) {
favoritesArray.push(itemHolder);
var storage = window.localStorage;
storage.shopsFavorites = JSON.stringify(favoritesArray);
}
}
function exists() {
var alreadyExists = false;
var favoritesArray = getStoreArray();
for (var key in favoritesArray) {
if (favoritesArray[key].title == itemHolder.title) {
//already exists
alreadyExists = true;
}
}
return alreadyExists;
}
function getStoreArray() {
//restores our favorites array if any or creates one
var storage = window.localStorage;
var favoritesArray = storage.shopsFavorites;
if (favoritesArray == null || favoritesArray == "") {
//if first time
favoritesArray = new Array();
} else {
//if there are already favorites
favoritesArray = JSON.parse(favoritesArray);
}
return favoritesArray;
}
And I have a favorites.html to present those as a list.
The problem I have is that the list doesn't update automaticly every time I add or remove items.
Here is my code for that:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Αγαπημένα</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<link href="favoritesDetails.css" rel="stylesheet" />
<script src="favoritesDetails.js"></script>
</head>
<body>
<div class="favoritesDetails fragment">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Αγαπημένα</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
<div class="mediumListIconTextItem">
<img src="#" class="mediumListIconTextItem-Image" data-win-bind="src: picture" />
<div class="mediumListIconTextItem-Detail">
<h4 data-win-bind="innerText: title"></h4>
<h6 data-win-bind="innerText: text"></h6>
</div>
</div>
</div>
<div id="basicListView" data-win-control="WinJS.UI.ListView"
data-win-options="{itemDataSource : DataExample.itemList.dataSource,
itemTemplate: select('#mediumListIconTextTemplate')}">
</div>
</section>
</div>
</body>
</html>
And here is the JavaScript code:
// For an introduction to the Page Control template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232511
var dataArray = [], shopsArray = [];
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
var nav = WinJS.Navigation;
var ui = WinJS.UI;
shopsArray = getStoreArray();
if (shopsArray) {
for (var key in shopsArray) {
var group = { title: shopsArray[key].title, text: shopsArray[key].subtitle, picture: shopsArray[key].backgroundImage, description: shopsArray[key].description, phoneNumbers: shopsArray[key].content };
dataArray.push(group);
}
var dataList = new WinJS.Binding.List(dataArray);
// Create a namespace to make the data publicly
// accessible.
var publicMembers =
{
itemList: dataList
};
WinJS.Namespace.define("DataExample", publicMembers);
}
WinJS.UI.Pages.define("/pages/favoritesDetails/favoritesDetails.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
},
unload: function () {
},
updateLayout: function (element, viewState, lastViewState) {
}
});
})();
function getStoreArray() {
//restores our favorites array if any or creates one
var storage = window.localStorage;
var favoritesArray = storage.shopsFavorites;
if (favoritesArray == null || favoritesArray == "") {
//if first time
favoritesArray = new Array();
} else {
//if there are already favorites
favoritesArray = JSON.parse(favoritesArray);
}
return favoritesArray;
}
So how can I update the favorites HTML page when new favorites are stored/removed in the localDB? can i add event listeners there?
Is the code that stores favorites a part of the same app?
If so, I would consider adding the favorite to the underlying WinJS.Binding.list that you're using to bind to the ListView, and then store the updated list info in the DB, rather than trying to react to changes in the DB from the ListView.
Have a look at the following sample, which shows how to update a ListView dynamically:
http://code.msdn.microsoft.com/windowsapps/ListView-custom-data-4dcfb128/sourcecode?fileId=50893&pathId=1976562066
Hope that helps!