This is my first program and I am quite not sure on how to complete my codes. I am trying to create a new transaction, where for a supplier there will be multiple inventory types. I am lost on how to add the inventory types to a list using Partial View. Any guidance on how to structure the code will be greatly appreciated. Here are my codes:
ViewModels:
public class InventoryTransactionParent
{
[Key]
public int InventoryTransactionID { get; set; }
[ForeignKey("InventoryTransactionType")]
[Display(Name = "Transaction Type")]
public int InventoryTransactionTypeID { get; set; }
public virtual InventoryTransactionType InventoryTransactionType { get; set; }
[Display(Name = "Supplier")]
[ForeignKey("Supplier")]
public int? SupplierID { get; set; }
public virtual Supplier Supplier { get; set; }
[Display(Name = "Transaction Date (From previous month only)")]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime InventoryTransactionDate { get; set; }
[Display(Name = "Receipt/Invoice No.")]
public string InventoryTransactionReceipt { get; set; }
[Display(Name = "Transaction By")]
public string InventoryTransactionBy { get; set; }
[Display(Name = "Created On")]
public DateTime InventoryTransactionCreatedDateTime { get; set; }
[Display(Name = "Created By")]
public string InventoryTransactionCreatedBy { get; set; }
public bool InventoryTransactionCancelled { get; set; }
public int? InventoryTransactionCancelledSourceID { get; set; }
public List<InventoryTypeChild> InventoryTypeChilds { get; set; }
}
public class InventoryTypeChild
{
[ForeignKey("InventoryType")]
[Display(Name = "Inventory Type")]
public int InventoryTypeID { get; set; }
public virtual InventoryType InventoryType { get; set; }
[Display(Name = "Quantity")]
public decimal InventoryTransactionQuantity { get; set; }
[Display(Name = "Price per Item")]
public decimal InventoryTransactionPrice { get; set; }
[Display(Name = "Remarks (1000 characters)")]
[DataType(DataType.MultilineText)]
public string InventoryTransactionRemarks { get; set; }
}
View:
#model Inventory.ViewModels.InventoryTransactionParent
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>In Transaction</legend>
<div class="editor-label">
#Html.LabelFor(model => model.SupplierID, "Supplier")
</div>
<div class="editor-field">
#Html.DropDownList("SupplierID", String.Empty)
#Html.ValidationMessageFor(model => model.SupplierID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.InventoryTransactionDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.InventoryTransactionDate, "TransactionDate")
</div>
<div class="editor-label">
#Html.LabelFor(model => model.InventoryTransactionReceipt)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.InventoryTransactionReceipt)
#Html.ValidationMessageFor(model => model.InventoryTransactionReceipt)
</div>
<div id="inventorytypes">
#using (Html.BeginForm()) {
<table>
<tr>
<td>#Html.LabelFor(model => Model.InventoryTypeChilds[0].InventoryTypeID)</td>
<td>#Html.LabelFor(model => Model.InventoryTypeChilds[0].InventoryTransactionPrice)</td>
<td>#Html.LabelFor(model => Model.InventoryTypeChilds[0].InventoryTransactionQuantity)</td>
<td>#Html.LabelFor(model => Model.InventoryTypeChilds[0].InventoryTransactionRemarks)</td>
<td></td>
</tr>
#{
if (Model.InventoryTypeChilds != null)
{
for (int i = 0; i < Model.InventoryTypeChilds.Count(); i++)
{
<tr>
<td>
#Html.DropDownList("InventoryTypeID", String.Empty)
#Html.ValidationMessageFor(model => model.InventoryTypeChilds[i].InventoryTypeID)
</td>
<td>
#Html.EditorFor(model => Model.InventoryTypeChilds[i].InventoryTransactionPrice)
#Html.ValidationMessageFor(model => Model.InventoryTypeChilds[i].InventoryTransactionPrice)
</td>
<td>
#Html.EditorFor(model => Model.InventoryTypeChilds[i].InventoryTransactionQuantity)
#Html.ValidationMessageFor(model => Model.InventoryTypeChilds[i].InventoryTransactionQuantity)
</td>
<td>
#Html.EditorFor(model => Model.InventoryTypeChilds[i].InventoryTransactionRemarks)
#Html.ValidationMessageFor(model => Model.InventoryTypeChilds[i].InventoryTransactionRemarks)
</td>
<td>
<input type="submit" value="Add" />
</td>
</tr>
}
}
}
</table>
}
</div>
<p>
<input type="submit" value="In" />
</p>
</fieldset>
}
Controller (still very rough):
public ActionResult InMultipleTransaction()
{
ViewBag.InventoryTypeID = new SelectList(db.InventoryTypes, "InventoryTypeID", "InventoryTypeName");
ViewBag.SupplierID = new SelectList(db.Suppliers, "SupplierID", "SupplierName");
InventoryTransactionParent itp = new InventoryTransactionParent();
itp.InventoryTypeChilds = new List<InventoryTypeChild>();
itp.InventoryTypeChilds.Add(new InventoryTypeChild()
{
});
return View(itp);
}
You don't need to use Partial Views in one-to-many relationship. Partial Views are useful if parent and child objects are being created at the same time, mostly happens in one-to-one relationship (But even then, most people use ViewModels). But in your case, you have to have parent object created first then you add many child objects.
This Plural Sight video would be a good way to start. There is a free trial
Related
create component
<?php
namespace App\Http\Livewire\Teacher\Lesson;
use App\Models\Course;
use App\Models\Lesson;
use Illuminate\Support\Facades\Lang;
use Livewire\Component;
use Livewire\WithFileUploads;
class Create extends Component
{
use WithFileUploads;
public $new_row;
public $authUser;
protected $listeners = ['store'];
public function updatedNewRowImage()
{
$this->validate([
'new_row.video' => 'required|file|max:3000|mimes:mp4',
]);
}
public function mount() {
$this->authUser = \Auth::user();
}
public function rules()
{
return [
'new_row.name.ar' => "required|min:3",
'new_row.name.en' => "required|min:3",
'new_row.content.ar' => "required|min:3",
'new_row.content.en' => "required|min:3",
'new_row.course_id' => 'required|exists:courses,id',
'new_row.video' => 'nullable|file',
'new_row.status' => 'required',
'new_row.duration' => 'required|numeric',
];
}
public function store()
{
$this->validate();
$video_name = $this->new_row['video']->store('video/lessons', 'public');
$this->new_row['video'] = basename(parse_url($video_name, PHP_URL_PATH));
$this->new_row['teacher_id'] = $this->authUser['id'];
Lesson::create($this->new_row);
$this->emit('alert', ['type' => 'success', 'message' => Lang::get('message.success_response_message')]);
return redirect()->route('teacher.lessons.index');
}
//
public function render()
{
$courses = Course::all();
return view('livewire.teacher.lesson.create', compact('courses'));
}
}
Lesson Model
<?php
namespace App\Models;
use App\Traits\FilterScopeModelTrait;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;
class Lesson extends Model
{
use HasFactory, FilterScopeModelTrait,HasTranslations;
public $translatable = ['name','content'];
protected $guarded = [];
protected function video(): Attribute
{
return Attribute::make(
get: fn($value) => ($this->attributes['video'] ?? false) ? asset('storage/videos/lessons/' . $this->attributes['video']) : '',
);
}
}
blade file
<div class="form-group col-md-6 mb-2">
<label class="col-sm-6 col-form-label" for="inputAdsVideo">#lang('teacher.video')</label>
<div class="col-sm-10 col-lg-10 col-md-2">
<input type="file" name="new_row.video" wire:model="new_row.video " id="Video"
class="form-control is-invalid"
>
</div>
#error('new_row.video')
<small class=" text text-danger" role="alert">
<strong>{{ $message }}</strong>
</small>
#enderror
</div>
migration
Schema::create('lessons', function (Blueprint $table) {
$table->id();
$table->json('name')->nullable();
$table->json('content')->nullable();
$table->foreignId('teacher_id')->nullable()->constrained();
$table->foreignId('course_id')->nullable()->constrained();
$table->float('duration')->nullable();
$table->text('video')->nullable();
$table->enum('status',['pending','publish']);
$table->timestamps();
});
crude of lessons to insert data in data base
when i try to insert data in data base this me undefined key
of video
pleas help to solve and try to upload video all data uploaded with me except video
Am using Lit2.0, Material Web components, Django (backend).
one reference: https://www.thinktecture.com/en/web-components/flaws/
I don't understand how to submit form data from Lit component to backend (Django)
form.html contains Lit component (basic-form)
<form id="id_demo" method="post" action="">
{% csrf_token %}
<basic-form></basic-form>
<button type="submit" class="mdc-button mdc-button--raised">Submit</button>
</form>
basic-form is a Lit component and it contains Material web components
import {LitElement, html} from "lit";
// const template = document.createElement('template');
// template.innerHTML = `
// <slot></slot>
// `;
export class BasicForm extends LitElement {
static properties = {
form: '',
};
constructor() {
super();
// this.shadow = this.attachShadow({ mode: 'open' });
// this.shadow.appendChild(template.content.cloneNode(true));
}
render() {
return html`
<mwc-textfield name="first_name"></mwc-textfield>
`;
}
}
customElements.define('basic-form', BasicForm);
Could someone guide me to the right direction.
You can take the value of textfield element on blur and save it as property of basic-form. Then on form submit you can take the basic-form.value property:
basic-form
export class BasicForm extends LitElement {
static properties = {
value: ''
}
onBlur() {
this.value = e.target.value;
}
render() {
return html`
<mwc-textfield name="first_name" #onBlur="${this.onBlur}></mwc-textfield>
`;
}
form.html
<form id="id_demo" method="post" action="">
{% csrf_token %}
<basic-form></basic-form>
<button type="submit" class="mdc-button mdc-button--raised">Submit</button>
</form>
<script>
const form = document.getElementById("id_demo");
const basicForm = form.querySelector('basic-form');
const onSubmit = (event) => {
console.log(basicForm.value);
}
form.addEventListener('submit', onSubmit);
</script>
Actually this is not that easy at all. You have to use ElementInternals: https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals
"The ElementInternals interface of the Document_Object_Model gives web developers a way to allow custom elements to fully participate in HTML forms."
That said here is an example:
<script type="module">
import {
LitElement,
html,
css
} from "https://unpkg.com/lit-element/lit-element.js?module";
class MyItem extends LitElement {
static get formAssociated() {
return true;
}
static get properties() {
return {
name: { type: String, reflect: true },
required: { type: Boolean, reflect: true },
value: { type: String }
};
}
constructor() {
super();
this.internals = this.attachInternals();
this.name = name;
this.required = false;
this.value = '';
this._required = false;
}
render() {
return html`
<label for="input"><slot></slot></label>
<input type="${this.type}" name="${this.name}" id="input" .value="${this.value}" ?required="${this.required}" #input="${this._onInput}">
`;
}
_onInput(event) {
this.value = event.target.value
this.internals.setFormValue(this.value);
}
firstUpdated(...args) {
super.firstUpdated(...args);
/** This ensures our element always participates in the form */
this.internals.setFormValue(this.value);
}
}
customElements.define("my-item", MyItem);
const formElem = document.querySelector('#formElem');
formElem.addEventListener('submit', event => {
event.preventDefault();
const form = event.target;
/** Get all of the form data */
const formData = new FormData(form);
formData.forEach((value, key) => console.log(`${key}: ${value}`));
});
</script>
<form id="formElem">
<my-item name="firstName">First name</my-item>
<button type="submit">Submit</button>
</form>
I'm trying to get data from person field in SharePoint. My code always returns 8 rows (its correct) but at items that consists of Person it returns [object Obejct].
enter image description here
export interface SPUser {
Pracovnik: String;
}
.
.
private getListData(): void {
this._getListData().then((response) => {
this._renderList(response);
});
}
private _renderList(items: SPUser[]): void {
let html: string = '<table class="TFtable" border=1 width=100% style="border-collapse: collapse;">';
html += `<th>Title</th>`;
items.forEach((item: SPUser) => {
if(item.Pracovnik != null) {
html += `
<tr> <td>${item.Pracovnik}</td> </tr>
`};
});
html += `</table>`;
const listContainer: Element = this.domElement.querySelector('#spGetListItems');
listContainer.innerHTML = html;
}
private async _getListData(): Promise<SPUser[]> {
return pnp.sp.web.lists.getByTitle("org_struktura").items.select("Pracovnik/ID").expand("Pracovnik").get().then((response) => {
return response;
});
}
public render(): void {
this.domElement.innerHTML = `
<div class="parentContainer" style="background-color: lightgrey">
<div style="background-color: lightgrey" id="spGetListItems" />
</div>
`;
this.getListData();
}
Any idea what is wrong please?
Sample demo to map SharePoint list item to a Type object.
export interface IReactItem{
Id:number,
Title:string,
Description:string,
User:{ID:number,EMail:string},
enableEdit:boolean
}
private async _getListData(): Promise<IReactItem[]> {
return pnp.sp.web.lists.getByTitle("TestList").items.select("Id,Title,Description,User/ID,User/EMail").expand("User").get().then((response:IReactItem[]) => {
return response;
});
}
There is a class in my app SL-Leg.It has some variables which would hold the values.
When i print object of this class then [object object] is being printed
but when i try to access the value of the class by myObject.line for example then there is an error undefined is not an object (evaluating self.context.$implicit.line
leglist is array which holds the objects from class SL'Leg.
<ion-header>
<ion-navbar>
<ion-title>showTripInfo</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-content class="show-trips">
<ion-list>
<ion-item-group *ngFor="let leg of legList" (click) = "showTripInfo(tp)">
<ion-card>
<table style="width:100%">
<tr>
<div class="page-show-trips.card-title">
<th item-width="100%">{{leg}} >> {{leg.line}}</th>
</div>
</tr>
<tr>
<div class="page-show-trips.card-subtitle">
<th item-width="100%">{{leg}} >> {{leg}}</th>
</div>
</tr>
</table>
<div ng-repeat="(key, value) in tp.LegList" > {{key}} {{value}} </div>
</ion-card>
</ion-item-group>
</ion-list>
</ion-content>
</ion-content>
SL-Leg is here
i
mport { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Address } from './sl-Address';
/*
Generated class for the SlTripClass page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
selector: 'page-sl-legs',
//templateUrl: 'sl-trip-class.html'
})
export class Leg {
// public from_time: String;
public legIndex: Number;
public enabled_TransportType: Boolean; // Default True
public enabled_LineNumber: Boolean; // Default true
public showHideLeg: Boolean; // Default true means show all legs
public filterLine: Boolean;
public filterDepartures: Boolean;
// ...:Common publiciables available in Travel /Walk
public journeyType : String;
// available via LegDetail
public origin: Address;
public destination: Address;
public name: String;
public type: String;
public idx: String;
public geomRef: String;
public legImageName: String;
//-- Only found in --------Walk
public dist: String;
public hide: String;
//-- Only found in --------Travel
public dir: String;
public line: String;
public journeyDetailRef: String;
public rtu_Message_Flag: Boolean;
public rtu_Message: String;
// constructor(public tripObjectFromSl: any,public navCtrl: NavController, public navParams: NavParams) {
constructor() {
this.legIndex = 0;
this.enabled_TransportType= true; // Default True
this.enabled_LineNumber= true;
this.showHideLeg= true;
this.filterLine= false;
this.filterDepartures;
this.journeyType= String();;
this.origin= new Address();
this.destination= new Address();
this.name= String();
this.type= String();
this.idx= String();
this.geomRef= String();
this.legImageName= String();
this.dist= String();
this.hide= String();
//-- Only found in --------Travel
this.dir= String();
this.line= String();
this.journeyDetailRef= String();
this.rtu_Message_Flag= true;
this.rtu_Message= String();
}
ionViewDidLoad() {
console.log('ionViewDidLoad SlTripClassPage');
}
}
The first object in the array LegList is null or undefined.
You could just put a null check
{{leg?.line}}
Also the legIndex value starts from 1.
I suppose you are inserting with for loop starting index 1.
I'm working on an application to track orders that are coming through a web application. The application won't sell products, and it's designed to track orders as they come in via phone.
I'm still new to ASP.NET MVC, so I'm still learning the ropes. I'm trying to use model binding to get this to work.
Here's my view model:
public class OrderDetailViewModel
{
public Order Order { get; set; }
public List<OrderLine> OrderLinesList { get; set; }
public OrderDetailViewModel()
{
this.Order = new Order();
List<OrderLine> OrderLines = new List<OrderLine>();
OrderLines = new List<OrderLine>();
OrderLines.Add(new OrderLine());
this.OrderLinesList = OrderLines;
}
public OrderDetailViewModel(Order order)
{
this.Order = order;
}
public string SalesRepName
{
get
{
ApplicationDbContext db = new ApplicationDbContext();
ApplicationUser Rep = db.Users.First(u => u.UserName == Order.SalesRep);
return Rep.FirstName + " " + Rep.LastName;
}
}
public IEnumerable<SelectListItem> CustomerList
{
get
{
var Db = new OrderContext();
var Customers = Db.Customers;
var AllCustomers = Customers.Select(c => new SelectListItem
{
Value = c.Id.ToString(),
Text = c.FirstName + " " + c.LastName
});
return AllCustomers;
}
}
public IEnumerable<SelectListItem> ProductList
{
get
{
var Db = new OrderContext();
var Products = Db.Products;
var AllProducts = Products.Select(p => new SelectListItem
{
Value = p.Id.ToString(),
Text = p.Name + ", " + p.Airshow + " - " + p.AirshowDate
});
return AllProducts;
}
}
}
Here's the data model for OrderLine:
public class OrderLine
{
[Key]
public int Id { get; set; }
[Required, Display(Name="Order Number")]
public int OrderId { get; set; }
[Required]
public int ProductId { get; set; }
[Required]
public int Quantity { get; set; }
[Required]
[DisplayFormat(ApplyFormatInEditMode=true, DataFormatString="{0:C}")]
public float Price { get; set; }
[Required, Display(Name="Tax Rate"), DisplayFormat(DataFormatString="{0:P}")]
public float TaxRate { get; set; }
public Nullable<float> Discount { get; set; }
public virtual Product Product { get; set; }
public virtual Order Order { get; set; }
}
And here's the View:
#model AirshowCouponsMvc.Models.OrderDetailViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>OrderDetailViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<table class="table table-striped table-responsive table-hover">
<tr>
<th colspan="2">Order Date: #Html.Label(String.Format("{0:MMMM d, yyyy}", DateTime.Now))</th>
<th colspan="2">Customer: #Html.DropDownListFor(model => model.Order.CustomerId, Model.CustomerList)</th>
</tr>
<tr>
<th>
#Html.LabelFor(model => model.Order.OrderLines.FirstOrDefault().Product)
</th>
<th>
#Html.LabelFor(model => model.Order.OrderLines.FirstOrDefault().Quantity)
</th>
<th>
#Html.LabelFor(model => model.Order.OrderLines.FirstOrDefault().TaxRate)
</th>
<th>
#Html.HiddenFor(model => model.OrderLinesList)
</th>
</tr>
#foreach (AirshowCouponsMvc.Models.OrderLine item in Model.OrderLinesList)
{
<tr>
<td>
#Html.DropDownListFor(model => item.ProductId, Model.ProductList)
</td>
<td>
#Html.EditorFor(model => item.Quantity)
</td>
<td>
#Html.EditorFor(model => item.TaxRate)
</td>
<td>
#Html.HiddenFor(model => item.Price)
#Html.HiddenFor(model => item.OrderId)
#Html.HiddenFor(model => item.Id)
#Html.HiddenFor(model => item.Discount)
#Html.HiddenFor(model => item.Order)
#Html.HiddenFor(model => item.Product)
</td>
</tr>
}
<tr>
<td></td>
<td>#Html.ActionLink("Add line", "AddLine")</td>
<td>#if (Model.OrderLinesList.Count > 1) { #Html.ActionLink("Remove line", "RemoveLine") }</td>
</tr>
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10 pull-right">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Finally, here's the code for the controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(OrderDetailViewModel model)
{
if (ModelState.IsValid)
{
OrderContext db = new OrderContext();
model.Order.OrderDate = DateTime.Now;
model.Order.SalesRep = User.Identity.Name;
db.Orders.Add(model.Order);
foreach (var line in model.Order.OrderLines)
{
line.Price = line.Product.Price;
line.Discount = OrderDetailViewModel.DiscountRate(line.Quantity);
line.OrderId = model.Order.Id;
db.OrderLines.Add(line);
}
return RedirectToAction("Index");
}
return View(model);
}
Yes, I know that the controller doesn't process the list. I had used the property from the data model, then I read that you need to define a List as a property in the view model. I was in the middle of changing it to this, but when I hit a break at the beginning of the Create action, I noticed that the OrderLinesList is null.
Also, I read that in older version of ASP.NET MVC (at least I haven't seen it in reference to more recent versions of ASP.NET MVC) that you have to use a for loop instead of a foreach loop. I tried going that route, but I still had the problem of a null List.
Here's the code that I tried as a for loop in the Create view. This was inserted in place of the foreach loop currently shown:
#for (int i = 0; i < Model.OrderLines.Count(); i++)
{
<tr>
<td>
#Html.DropDownListFor(model => model.OrderLines[i].ProductId, Model.ProductList)
</td>
<td>
#Html.EditorFor(model => model.OrderLines[i].Quantity)
</td>
<td>
#Html.EditorFor(model => model.OrderLines[i].TaxRate)
</td>
<td>
#Html.HiddenFor(model => model.OrderLines[i].Id)
#Html.HiddenFor(model => model.OrderLines[i].Price)
#Html.HiddenFor(model => model.OrderLines[i].Discount)
#Html.HiddenFor(model => model.OrderLines[i].OrderId)
#Html.HiddenFor(model => model.OrderLines[i].Order)
#Html.HiddenFor(model => model.OrderLines[i].Product)
</td>
</tr>
}
My end goal is to be able to track multiple line items for each order, preferably with model binding.
I've read through quite a few references to try to get this to work, including:
http://seesharpdeveloper.blogspot.com/2012/05/mvc-model-binding-to-list-of-complex.html
Model binding generic list is null in asp.net mvc
MVC3 Non-Sequential Indices and DefaultModelBinder
ASP.NET MVC 4 - for loop posts model collection properties but foreach does not
I've followed the advice in these, and it's not working for me.
I would appreciate any help on getting this fixed.