Populate Knockout's observable array from Razor - asp.net-core

I'm trying to implement error handling in ASP.NET so that if there is an error the user will get the error message, then be able to go back and have the previous state restored. I'm using ASP.NET Core and Knockout (not my implementation). I want to update "signerFields" with the model from the server (Model.SignersJson). How would I do this?
Signer.js
function SignerViewModel() {
var self = this;
self.signerFields = ko.observableArray([]);
self.guarantorFields = ko.observableArray([]);
self.companyGuarantorFields = ko.observableArray([]);
...
Signer.cshtml
<div data-bind="foreach: signerFields, visible: signerFields().length > 0">
<div class="row">
<div class="col-lg-10">
<div>
#*Header Company signers section*#
<div class="row" data-bind="visible: isCompany() && !anySigner() && !isInvitation()" style="display: none">
<div class="col-lg-4">
<b>FullName</b>
</div>
#*<div class="col-lg-3">
<b>LastName </b>
</div>*#
<div class="col-lg-4">
<b>Role </b>
</div>
<div class="col-lg-3">
<b>Contact_Information</b>
</div>
</div>
</div>
</div>
...
#section scripts
{
<script src="~/Scripts/Signer.js"></script>
var serverSigners = JSON.parse(#Html.Raw(Json.Encode(Model.SignersJson)));
var observableData = ko.mapping.fromJS(serverSigners);
var viewModel = new SignerViewModel();
viewModel.signerFields(observableData); // <-- How?
}
I get no error messages, nothing.

There is a lot of unknowns with this one, but here is a working example using the information we have at hand. One thing I noticed was when creating this sample was that I assumed the data comming from Razor was in an array. and when the array is passed into the mapping component it comes out as an observable array. This meant that the data going into the signerFields was probably not what you were expecting and ended up having an observableArray with one object which itself was an observable array. Adding round brackets to observableData() means that you get the data out of the observable and you can then pass it into the signerFields as an array of objects.
Hope that made sense.
function SignerViewModel() {
var self = this;
self.signerFields = ko.observableArray([]);
self.guarantorFields = ko.observableArray([]);
self.companyGuarantorFields = ko.observableArray([]);
}
var serverSigners = [{'fullname':'Test Name', 'lastName': 'Name', 'role': 'Test Role', 'contactInformation': '123 Seasame Street NY, US', 'isCompany': true, 'anySigner': false, 'isInvitation': false}];
var observableData = ko.mapping.fromJS(serverSigners);
var viewModel = new SignerViewModel();
viewModel.signerFields(observableData());
ko.applyBindings(viewModel)
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<div data-bind="foreach: signerFields, visible: signerFields().length > 0">
<div class="row">
<div class="col-lg-10">
<div>
<div class="row" data-bind="visible: isCompany() && !anySigner() && !isInvitation()">
<div class="col-lg-4">
<b>FullName: </b><span data-bind="text: fullname"></span>
</div>
<div class="col-lg-3">
<b>LastName: </b><span data-bind="text: lastName"></span>
</div>
<div class="col-lg-4">
<b>Role: </b><span data-bind="text: role"></span>
</div>
<div class="col-lg-3">
<b>Contact Information: </b><span data-bind="text: contactInformation"></span>
</div>
</div>
</div>
</div>
</div>
</div>

Related

VUE's focus() method return a console error? How to use it correctly?

I'm trying to focus on several elements of my form but the first one, despite being applied, returns an error by console.
This is my template:
<div class="container">
<div class="col-xs-12">
<div class="row">
<h1 class="animal-title">Your selection is : </h1>
</div>
<div class="wrapper">
<form class="first-form" #submit.prevent="onSubmit">
<div class="image-wrapper">
<div class="sel-image">
<div v-on:click="imageSelected = true" v-for="item in items" v-bind:key="item.id">
<label>
<input
type="radio"
name="selectedItem"
ref="item"
:value="item.id"
v-model="itemFormInfo.selectedItem"
#change="onChangeItem($event)"
/>
<img v-if="item.id === 1" src="../../assets/1.png" />
<img v-if="item.id === 2" src="../../assets/2.png" />
<img v-if="item.id === 3" src="../../assets/3.png" />
</label>
<p class="cie-animal-subtitle">{{item.name}}</p>
</div>
</div>
</div>
<div class="form-select">
<div v-show="filteredStock && (imageSelected || itemFormInfo.selectedItem) > 0">
<h1 v-if="this.itemName === 'Phone' || this.itemName === 'Tablet'" for="selectedItem" ref="itemVisible">
Select the brand of your <span>{{this.itemName}}</span> :
</h1>
<h1 v-if="this.itemName === 'PC'" for="selectedBreed" ref="itemVisible">
Select the type of your <span>{{this.itemName}}</span> :
</h1>
<select
ref="brand"
class="form-control"
id="selectedBrand"
v-model="itemFormInfo.selectedBrand"
#change="onChangeBrand($event)">
<option v-for="brand in filteredBrand" v-bind:key="brand.name">{{ brand.name }}</option>
</select>
<div v-show="this.isBrandSelected">
<h1>What are you going to use your
<span>{{itemName}}</span> for ?
</h1>
<input
type="text"
id="componentName"
ref="componentName"
class="form-control fields"
style="text-transform: capitalize"
v-model="itemFormInfo.component"
#keypress="formChange($event)"
/>
<div class="loader-spinner" v-if="loading">
<app-loader/>
</div>
</div>
</div>
</div>
<div class="service-options" v-show="isComponentCompleted">
<div class="from-group">
<h1>
Here are the options for your <span>{{this.itemFormInfo.component}}</span> :
</h1>
<div class="services">
<div class="column-service" v-for="option in options" v-bind:key="option.name">
<div class="service-name">{{option.name}}</div>
<div class="service-price">{{option.price.toString().replace(".", ",")}} </div>
</div>
</div>
and here my first method
onChangeItem(event) {
let item = event.target._value;
this.itemName = this.getItemName(item);
if (this.isItemSelected = true) {
this.isItemSelected = false;
this.isComponentCompleted = false;
this.isLoaderFinished = false;
this.itemFormInfo.name = ""
}
this.$refs.item.focus();
},
in this function that I control my first input, the focus is working but it returns me by console the following error:
"this.$refs.item.focus is not a function at VueComponent.onChangeItem"
I have seen some references to similar cases where they involved the reference in a setTimeout or used the this.$nextTick(() => method but it didn't work in my case.
What am I doing wrong?
How can I focus on the next select with ref brand, once I have chosen the value of the first input?
Thank you all for your time and help in advance
How can I focus on the next select with ref brand, once I have chosen the value of the first input?
You want to put focus on brand but your onChangeItem handler is calling this.$refs.item.focus() (trying to focus item). Seems strange to me...
Reason for the error is you are using ref inside v-for.
Docs: When used on elements/components with v-for, the registered reference will be an Array containing DOM nodes or component instances
So the correct way for accessing item ref will be this.$refs.item[index].focus().
Just be aware that right now v-for refs do not guarantee the same order as your source Array - you can find some workarounds in the issue discussion...

I want to show Filtered products in Vue Js based upon the selection made by user in 3 diffrent parameters from All products

This is step 1 which will appear & user will select one category from this
<div class="w-100 text-center step-div py-5">
<h3>step 1 </h3>
<p class="step-p"> for Men, Women or Unisex</p>
<div class="container">
<div id="categorytype" class="responsive">
<div v-for="(type,typeIndex) in types" class="filter-slider-div col-4 p-5" #click= "addfiltertype(typeIndex,type.typeslug)">
<img :src="type.typeImage" class="filter-img mx-auto">
<p>{{type.typename}}</p>
</div>
</div>
</div>
</div>
Out put will be something like Men,Women,Both,Kids etc & On click It is saving slug of this type. which I'll share below,
<h3>step 2 </h3>
<p class="step-p">Select your case size</p>
<div class="container">
<div id="categorydials" class="responsive">
<div v-for="(dial,dialIndex) in dials" class="filter-slider-div col-4 p-5" #click= "addfilterdial(dialIndex,dial.dialname)">
<img :src="dial.dialimage" class="filter-img mx-auto">
<p>{{dial.dialname}}mm</p>
</div>
</div>
</div>
In step 2 User will select Size it can be anything,
<h3>step 3 </h3>
<p class="step-p">Select your case colour</p>
<div class="container">
<div id="categorycolors" class="responsive">
<div v-for="(color,colorIndex) in colors" class="filter-slider-div p-5" #click= "addfiltercolor(colorIndex,color.colorslug)">
<img :src="color.colorimage" class="filter-img mx-auto">
<p>{{color.colorname}}</p>
</div>
</div>
</div>
In Step 3 User will select Colour
Now After this I am updating & saving the slug of these categoies in my js in method
Here is code how my Categories are coming from & saving the category slug in typeslugFilter
I used alert Js to check if it's working & saving correctly or not & It's Saving the exact slug,
var filters = new Vue ({
el: '#categorytype',
data:{
types: [
{
typeId: 1,
typename: 'Men',
typeImage: 'assets/images/filter1.png',
typeslug: 'men',
},
{
typeId: 2,
typename: 'Women',
typeImage: 'assets/images/filter2.png',
typeslug: 'women',
},
{
typeId: 3,
typename: 'Watches',
typeImage: 'assets/images/filter3.png',
typeslug: 'both',
}
] },
methods: {
addfiltertype (typeIndex,typeslug) {
this.typeslugFilter = typeslug;
// alert(this.typeslugFilter+ '+' + typeslug);
}
}
});
Consider similar code for other two categories with variable dialnameFilter & colorslugFilter,
Now I am trieng to fetch filtered products using below code it's not working for me as of now
I am getting my products from json file & they are working fine I am using typeslug & dialname as category type in single product details & using productslider as el: element .
<div id="productslider" class="container py-5">
<p>{{typeslugFilter}}</p>
<div v-for="(variant,variantIndex) in variants" v-if="typeslugFilter === typeslug && dialnameFilter === dialname">
<div class="watch-slider-div">
<img :src="variant.variantImage" class="w-100 py-3">
</div>
</div>
</div>
Please help me out in this If any tech geek an help will be appreciated

How to close Modal de Materialize CSS with Vue

I am trying to close a Modal of Materialize CSS if the validation is correct but I can not find the form.
The simplest thing was to do a type validation:
v-if = "showModal" and it works but leaves the background of the Modal and although click does not disappear. The background is a class named 'modal-overlay'
This is my code:
<i class="material-icons modal-trigger tooltipped" style="margin-left: 2px;
color:#ffc107; cursor:pointer;" #click="getById(article), fillSelectCategories(),
titleModal='Edit', type='edit'" data-target="modal1">edit</i>
I imported M from the JS file of MaterilizeCSS
import M from "materialize-css/dist/js/materialize.min";
Method:
update(){
var elem = document.querySelectorAll('.modal');
var instance = M.Modal.getInstance(elem);
console.log(instance)
That returns 'undefined'
I tried this too on the update() method:
var elem = document.querySelectorAll('.modal');
elem.close();
M.Modal.close()
I initialize the modal from mounted and it works fine but I can not close it at the moment I require it.
mounted(){
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems, options);
}
But I know what else to try :(
It really is difficult to know why things aren't working for you without looking further into your code, but I've created this simple example to demonstrate how it could be done ..
new Vue({
el: "#app",
data: {
modalInstance: null,
closeAfterTimeElapsed: true,
seconds: 1
},
mounted() {
const modal = document.querySelector('.modal')
this.modalInstance = M.Modal.init(modal)
const select = document.querySelector('select');
M.FormSelect.init(select);
M.updateTextFields();
},
methods: {
handleClick() {
if (this.closeAfterTimeElapsed) {
setTimeout(() => { this.modalInstance.close() }, this.seconds * 1000)
}
}
}
})
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<!-- Modal Trigger -->
<button #click="handleClick" data-target="modal1" class="btn modal-trigger">Modal</button>
<!-- Modal Structure -->
<div id="modal1" class="modal">
<div class="modal-content">
<h4>Modal Header</h4>
<p>A bunch of text</p>
</div>
<div class="modal-footer">
Agree
</div>
</div>
<br>
<br>
<div class="row">
<div class="input-field col s6">
<select v-model="closeAfterTimeElapsed">
<option :value="false">False</option>
<option :value="true">True</option>
</select>
<label>Close Modal After</label>
</div>
<div class="input-field col s6">
<input id="seconds" type="number" v-model="seconds">
<label for="seconds">Seconds</label>
</div>
</div>
</div>
See this JSFiddle

Visualforce remote call not working with safari

I am developing an application using angularjs and visualforce remote calling.
The application works right in all the browser except in Safari. When the application is run on Safari browser it is not able to communicate to the server
returning
"Unable to connect to server( Communication failed)".
Code snippet
Apex Controller
global class UsaTAevaluationCtrl{
#RemoteAction
public static string getkeyvalue(string username,string key)
{
string interviewInviteId1;
system.debug(username+'OOOOOOOOOO'+key);
interviewInviteId1='False';
Tech_Screen_Invites__c t=new Tech_Screen_Invites__c();
try
{
t=[select id,name from Tech_Screen_Invites__c where Name=:username];
string recordkey=t.id;
if(t.id!=null)
{
interviewInviteId1=t.id;
recordkey=string.valueof(t.id);
if(recordkey.length()==18)
recordkey=recordkey.left(15);
if(recordkey.right(3)==key)
interviewInviteId1=t.id;
}
else
{}
}catch(exception e){}
return interviewInviteId1;
}
}
Visualforce page
<apex:page controller="UsaTAevaluationCtrl" showHeader="false" standardStylesheets="false" docType="html-5.0">
<apex:form >
// include statements
....
<script>
var services = (function(){
return function (userName, password) {
var deferred = $.Deferred();
Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.UsaTAevaluationCtrl.getkeyvalue}',
userName,
password,
function (result, event){
console.log("Result -> ", result);
});
return deferred.promise();
}
})()
</script>
....
<div class="container" ng-app="TechEval" ng-controller="evalform" ng-init="initEvent()">
<div class="row evaluation-row">
<div class="col-md-12 col-xs-12"> </div>
</div>
<div class="row evaluation-row" ng-show="isAuthenticationSuccess">
<div class="col-md-12 col-xs-12 alert alert-danger score-alert">Invalid Credentials</div>
</div>
<div class="row evaluation-row">
<div class="col-md-3 col-xs-12">
<h1 class="skill-title">User Name</h1>
</div>
<div class="col-md-9 col-xs-12">
<div class="skill-new">
<input name='_username' id='userinput' ng-model='_username' required="required"></input>
</div>
</div>
</div>
<div class="row evaluation-row">
<div class="col-md-12 col-xs-12"></div>
</div>
<div class="row evaluation-row">
<div class="col-md-3 col-xs-12">
<h1 class="skill-title">Token</h1>
</div>
<div class="col-md-9 col-xs-12">
<div class="skill-new">
<input name="_password" id="passvalue" type="password" ng-model='_password' required="required"></input>
</div>
</div>
</div>
<div class="row btn-row">
<div class="col-md-3 col-xs-12"> </div>
<div class="col-md-9 col-xs-12">
<div class="skill-new">
<button class="btn btn-primary" style="margin-left:92px;" ng-click="Authentication()">Submit</button>
</div>
</div>
</div>
</div>
</apex:form>
</apex:page>
Code in Angular Controller
var EvalApp = angular.module('TechEval', ['ui.bootstrap']);
EvalApp.controller('evalform', function ($scope, $log, $q) {
$scope.Authentication = function () {
services.getKeyValue($scope._username,
$scope._password,
function (result, event){
console.log("Result -> ", result);
});
}
}
Functionality
When user enter username and password and hits submit button the remote service is to be called.
If you check Supported Browsers for Salesforce Classic page, you find:
Apple Safari versions 8.x on Mac OS X There are no configuration
recommendations for Safari. Apple Safari on iOS isn’t supported for
the full Salesforce site. Safari isn’t supported for:
The Salesforce console
Salesforce CRM Call Center built with CTI Toolkit versions below 4.0
Salesforce Wave Analytics
Are you sure that your OS/Safari version are compatible with it?

Aurelia -- Route Change on Form Submission Issue

Aurelia newbie here and I have hit a wall.
So, this code works just fine and the route change happens, but it only happens after the Submit button on the home.html file is clicked TWICE. On the first Submit button click, I get the following error: ERROR [app-router] Error: Route not found: /anonymous-wow-armory-profile/.
My question is why does it work after two form submissions, but not the first one? I know I am missing something in the process here.
home.html
<template>
<div class="container-fluid">
<div class="row">
<div class="col-md-12 nav-home text-center">
Create Profile
Bug Report
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="logo">
<img src="dist/assets/images/logo.png" alt="Logo" />
</div>
</div>
</div>
<div class="row row-bottom-pad">
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="profile-creation-box">
<div class="box-padding">
<strong>Masked Armory</strong> is the most well known anonymous World of Warcraft (WoW) profile source in the Real Money Trading (RMT) market. We take everything to the next level with offering alternate gear sets, sorted reputation display, Feat of Strength / Legacy achievement display, and much more!<br /><br />
Come make a profile at Masked Armory today and see that we are the best solution for all of your anonymous WoW Armory profile needs!
</div>
</div>
</div>
<div class="col-md-4"></div>
</div>
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4 container-bottom-pad">
<div class="profile-creation-box">
<div class="box-padding">
<form class="form-horizontal" role="form" submit.delegate="submit()">
<div class="form-group">
<label class="col-sm-3 control-label">Region</label>
<div class="col-sm-9">
<label class="radio-inline">
<input type="radio" name="region_name" value="us" checked.bind="postData.region"> United States
</label>
<label class="radio-inline">
<input type="radio" name="region_name" value="eu" checked.bind="postData.region"> Europe
</label>
</div>
</div>
<div class="form-group">
<label for="server_name" class="col-sm-3 control-label">Server</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="server_name" placeholder="Server Name" value.bind="postData.serverName">
</div>
</div>
<div class="form-group">
<label for="character_name" class="col-sm-3 control-label">Character</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="character_name" name="character_name" placeholder="Character Name" value.bind="postData.characterName">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<div class="checkbox">
<label>
<input type="checkbox" id="altgear" name="altgear"> Add Alternate Gearset
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-danger">Create Armory Profile</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="col-md-4"></div>
</div>
</div>
</template>
home.js
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-http-client';
import {Router} from 'aurelia-router';
#inject(Router)
export class Home {
postData: Object = {};
data: string = '';
code: string = '';
loading: boolean = false;
http: HttpClient = null;
apiUrl: string = 'http://localhost:8000/api/v1';
constructor(router) {
this.http = new HttpClient().configure(x => {
x.withBaseUrl(this.apiUrl);
x.withHeader('Content-Type', 'application/json');
});
this.maRouter = router;
}
submit() {
console.log(this.postData);
this.http.post('/armory', JSON.stringify(this.postData)).then(response => {
this.data = response.content;
this.code = response.statusCode.toString();
this.loading = false;
});
this.maRouter.navigateToRoute('armory', {id: this.data});
}
}
armory.js
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-http-client';
export class Armory {
postData: Object = {};
data: string = '';
code: string = '';
loading: boolean = false;
http: HttpClient = null;
apiUrl: string = 'http://localhost:8000/api/v1';
profileId: number = 0;
constructor() {
this.loading = true;
this.http = new HttpClient().configure(x => {
x.withBaseUrl(this.apiUrl);
x.withHeader('Content-Type', 'application/json');
});
}
activate(params, routeConfig) {
this.profileId = params.id;
this.getArmoryData();
}
getArmoryData() {
return this.http.get("/armory/" + this.profileId).then(response => {
this.data = response.content;
console.log(this.data);
this.code = response.statusCode.toString();
this.loading = false;
});
}
}
What am I missing here?
Thanks for your help!
Please, provide your router configuration
Anyway I see some issues already. You try to navigate when this.data is not set, just wait for response:
this.http.post('/armory', JSON.stringify(this.postData)).then(response => {
this.data = response.content;
this.code = response.statusCode.toString();
this.loading = false;
this.maRouter.navigateToRoute('armory', {id: this.data});
});
and we do activate page only if this.getArmoryData() succeed here (if needed), also canActivate() maybe used too
activate(params, routeConfig) {
this.profileId = params.id;
return this.getArmoryData();
}
also would be better to set this.loading = true;, inside armory .activate() and in home.js in submit() before sending data