Polymer 2: Transfer property values among different pages - data-binding

I downloaded Skeleton-starter-kit application and started creating my new web page project in Polymer. The application has 3 different pages. On the first page I used iron-ajax and app-storage to connect to the API and store its values to the local storage. Now I would like to use data stored in that local storage on the other two pages of the project but I dont know how. I tried with this.$.propertyname but I only got undefined. I would appreciate any kind of help.
First page:
<dom-module id="first-page">
<iron-ajax
auto
url="http://api.blog.diamondappgroup.com/blog/posts"
handle-as="json"
last-response="{{ajaxResponse}}">
</iron-ajax>
<app-indexeddb-mirror
key="posts"
data="{{ajaxResponse.data}}"
persisted-data="{{persistedData}}">
</app-indexeddb-mirror>
<template is="dom-repeat" items={{persistedData}} as="data">
<div id="{{index}}" class="imageTextContainer1" on-click="showPost">
<img id="{{index}}" src$="{{openedBlogImage}}" alt="Image Not Found" on-click="showPost"/>
<h3 id="{{index}}" class="h3heading" on-click="showPost"> {{openedBlogName}} </h3>
<p id="{{index}}" class="text" on-click="showPost">{{openedBlogBody}}</p>
</div>
</template>
<script>
class FirstPage Polymer.Element {
static get is() { return "first-page"; }
static get properties() { return {
persistedData: {
type: Array
},
idnumber: {
type: Number
value: 5
},
openedBlogImage: {
type: String
},
openedBlogName: {
type: String
},
openedBlogBody: {
type: String
}
}}
json(obj) {
return JSON.stringify(obj, null, 2);
}
showPost(event){
var id = parseInt(event.target.id);
this.idnumber = id;
console.log("Id: " + this.idnumber);
var image = this.persistedData[this.idnumber].images[0].path;
console.log("Image: " + image);
this.openedBlogImage = image;
var name = this.persistedData[this.idnumber].name;
console.log("Name: " + name);
this.openedBlogName = name;
var body = this.persistedData[this.idnumber].body;
console.log("Body: " + body);
this.openedBlogBody = body;
}
customElements.define(FirstPage.is, FirstPage);
Second page:
<div on-click="showPost">
<img src$="{{openedBlogImage}}" alt="Image Not Found"/>
<h3 class="h3heading"> {{openedBlogName}} </h3>
<p class="text">{{openedBlogBody}}</p>
</div>
When I click on the a link at the first page it redirect me to the second page. I would like to know how to use data stored on the first page at the second page through data binding.

Related

ASP.NET MVC: How to send the ids of the DOM Body elements on the client's browser TO the controller when navigating from the view

I am working on an ASP.NET MVC app (ASP.NET NOT ASP.NET Core).
When a View is rendered, the user can click on some buttons on the page to collapse or show divs associated with each button. The div changes its class depending on whether it is collapsed or shown. I am using bootstrap attributes for this, and it works fine.
Now I have a "Save" button on the page. When the user clicks on this button, I need to retrieve the ids and classes of the divs, and pass them TO the Controller (in an array/collection/dictionary whatever).
Is there a way/method in ASP.NET to send to the Controller the attributes (ids, classes, etc) of the DOM elements on the client's browser ?
Thanks
If you want to send some attributes of DOM to Controller, I have a way.
HTML:
<div id="demo-1" class="chosendiv other-className" data-code ="abc">Lorem Ipsum</div>
<div id="demo-2" class="chosendiv other-className" data-code ="xyz">Lorem Ipsum</div>
<div id="demo-3" class="other-className" data-code ="mnt">Lorem Ipsum</div>
<button id="btn-save" onclick="Save()">SAVE</button>
Javascript
<script>
function Save(){
var cds = document.getElementsByClassName('chosendiv');
var finder = [];
if(cds != null){
for(i = 0; i< cds.length; i++){
finder.push({
ID: cds[i].getAttribute('id'),
ClassName: cds[i].getAttribute('class'),
Code: cds[i].getAttribute('data-code')
})
}
}
//
// Send finder to Controller. You can use Ajax...
// A simple ajax call:
//
$.ajax({
url: '/Home/YourAction',
type: 'GET', //<---- you can use POST method.
data:{
myDiv: JSON.stringify(finder)
},
success: function(response){
// Your code
}
})
}
</script>
Your Controller
public class HomeController: Controller
{
public HomeController(){}
[HttpGet]
public void YourAction(string myDiv)
{
//A lot of ways for converting string to Object, such as: creating new class for model, ...
// I use Dictionary Class
List<Dictionary<string, string>> temp = new List<Dictionary<string, string>>();
if(!string.IsNullOrEmpty(myDiv))
{
try
{
temp = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(myDiv);
}
catch { // Do something if it catches error. }
}
// Get a element (at index) from temp if temp.Count()>0
// var id = temp.ElementAt(index)["ID"];
// var className = temp.ElementAt(index)["ClassName"];
// var code = temp.ElementAt(index)["Code"];
//
//Your code
//
}
//......
}
It would be great if my answer could solve your problem.
Based on the answer provided by #Gia Khang
I made few changes in order to avoid the issue of the length of the URL exceeding the maximum limit.
Instead of adding the element's classes to an array using JS, I add them to a string :
function Save() {
var cds = document.getElementsByClassName('chosendiv');
// I use as string instead of an array
var finder = "";
if(cds != null){
for(i = 0; i< cds.length; i++){
finder = finder + "id=" + cds[i].getAttribute('id') + "class=" + cds[i].getAttribute('class') + "data-code=" +cds[i].getAttribute('data-code')
}
}
// Send finder to Controller. You can use Ajax...
// A simple ajax call:
var myURL = "/{Controller}/{Action}"
$.ajax({
url: myURL,
type: "POST",
data: { ids:finder },
success: function (response) {
}
})
}
In the Controller Action I add a parameter named "ids" (this must be the same name as the identifier of the data object in the post request)and I extract the id, class, and data value from the ids string by a method in one of my Models classes (sorry I work with VB.NET not with C# and it will take me a lot of time to convert the code to C#. I use the Split method in VB to split the ids string several times: a first one by using "id=" as delimiter, then spiting each element in the resulting array by the second delimiter "class=", etc. I add the resulting elements to a collection)
The Controller Action looks like this:
public class HomeController: Controller
{
public HomeController(){}
[HttpPost]
public void YourAction(string ids)
{
Models.myClass.splitStringMethod(ids)
Return View()
}
}

ngStyle binding not working when using scope variable

I have the following component:
#Component({
template: `
<div class="container">
<div *ngFor="let connection of connections">
<div class="row">
<div class='col-2'>{{connection.arrivalTime}}</div>
<div class='col-1'>{{connection.delay}}</div>
<div class='col-2'>{{connection.actualArrivalTime}}</div>
<div class='col-1'>{{connection.icon}}</div>
<div class='col-1'><span [ngStyle]="{'background-color': connection.colors.bg}">{{connection.line}}</span></div>
<div class='col-3'>{{connection.direction}}</div>
<div class='col-2'>{{connection.cancelled}}</div>
</div>
</div>
</div>
styleUrls: ['../app.component.css', '../../simple-grid.css'],
})
export class ZVVComponent {
connections: PublicConnection[] = [];
displayDate: Date;
constructor(private zvvService: ZVVService) {
this.displayDate = new Date();
zvvService.getConnections(this.displayDate).subscribe(data => {
data.forEach( (connection) => {
this.connections.push(new PublicConnection(
connection.product.line,
connection.product.longName,
connection.product.direction,
connection.cancelled,
connection.product.icon,
connection.product.color,
connection.mainLocation.time,
connection.mainLocation.countdown,
connection.mainLocation.realTime.time,
connection.mainLocation.realTime.countdown,
connection.mainLocation.realTime.delay,
connection.mainLocation.realTime.isDelayed,
connection.mainLocation.realTime.hasRealTime
));
});
});
}
}
As you can see, I used ngStyle in one of the divs and want to bind it to the variable connection.colors.bg that contains a hex string of the color:
export class Color {
get fg(): string {
return this.fg;
}
get bg(): string {
return this.bg;
}
}
However, this doesn't work and the text remains black and the background white. What am I doing wrong? When I change it, and write red in it instead of the variable, the text shows up in red.
Here is the PublicConnection code:
import { Color } from './color';
export class PublicConnection {
constructor(
public line: string,
private name: string,
public direction: string,
public cancelled: boolean,
public icon: string,
public colors: Color,
public arrivalTime: string,
private countdown: string,
public actualArrivalTime: string,
private actualCountdown: string,
public delay: string,
private isDelayed: boolean,
private hasRealtimeData: boolean
) {
this.direction = this.direction.replace('ü', 'ü');
this.direction = this.direction.replace('ö', 'ö');
this.direction = this.direction.replace('ü', 'ü');
}
}
The issue is not with the ngStyle directive -- you are using that correctly. It is most likely the data not being loaded when the component first tries to render.
Since your data is asynchronous, I'm guessing that at the time the component is rendering and setting the background color, it has not yet received a color from the service.
Try using a safe navigation operator by changing connection.color.bg to connection.color?.bg in your template.
Read more about it here: https://angular.io/guide/template-syntax#the-safe-navigation-operator----and-null-property-paths

Display all items in an array property in Angular 2

I have a type script component that defines two interfaces like:
interface Project {
name: string;
activity: string;
lastBuildStatus: string;
lastBuildTime: string;
lastBuildLabel: string
webUrl: string;
}
interface GoArray {
projects: Array<Project>;
}
The components makes a call to an ASP Core controller to return an object with property 'Projects' Which itself is a list of 'Project' objects. So I believe this matches my interface definitions. In the controller I set an object of type GoArray to the result from the controller
export class GoComponent {
public projectsArray: GoArray;
constructor(private http: Http) {
}
public getPipelineStatus(chosenUsername: string, chosenPassword: string, chosenUrl: string) {
// debugger;
this.http.get('api/go/cctray?username=' + chosenUsername + '&password=' + chosenPassword + '&uri=' + chosenUrl).subscribe(result => {
this.projectsArray = result.json();
});
This seems to be returning data in the format I expect. But how do I then display all items in the array in my components HTML?
I've tried
<div *ngIf="projectsArray">
<div *ngFor='let project of projectsArray.projects'>
{{project.Name}}
{{project.Activity}}
</div>
Nothing gets rendered on the screen with this, but if I inspect the component using Augury, it appears as though the projectsArray is populated as I expected
How do I iterate over the list and display the properties of each of the objects?
Thanks
It should be,
<div *ngFor='let project of projectsArray.projects'>
{{project.name}}
{{project.activity}}
</div>

Make Knockout.JS subscribale globally available

I have an ASP.NET application and i am using Knockout JS for some minimal Tasks in my application. However i have some EditorTemplates that are calculating values to display. I want access to this values from some other EditorTemplates. I thought i might use the native pub/sub functionality with Knockout, meaning i would write in one EditorTemplate the notification code, like so:
new ko.subscribable().notifySubscribers(this.calculatedValue, "customTopic");
and then receive this value when it changes in my other EditorTemplate
new ko.subscribable().subscribe(function (newValue) {
alert(newValue);
}, this, "customTopic");
Of course, this code wont work, as i am creating a new ko.subscribable() everytime.
How can i create a single ko.subscribable that is available in all my Views?
First you need to define a new instance of subscribable variable globally.
Inside other sub view models subscribe to subscribable variable that you defined.
Notify any subscribers by using notifySubscribers whenever any updates happens.
Example : https://jsfiddle.net/kyr6w2x3/149/
View:
<div id="one">
<h1>MainVM:</h1>
<input type="text" data-bind="textInput:Name">
<hr>
</div>
//-------------------------------------------------
<div id="two">
<h1>SecondVM:</h1>
<div data-bind="text:NameSecondVM"> </div>
</div>
Model:
var shouterValueOfName = new ko.subscribable();
<script type="text/javascript">
var MainViewModel = function(){
var self = this;
self.Name = ko.observable();
self.Name.subscribe(function (newValue) {
newValue = newValue ? newValue + " Sent from MainVM" : "" ;
shouterValueOfName.notifySubscribers(newValue, "secondVMTakeThis");
}, self);
}
</script>
<script type="text/javascript">
var SecondViewModel = function(){
var self = this;
self.SecondVM = ko.observable();
self.NameSecondVM = ko.observable();
shouterValueOfName.subscribe(function (newValue) {
self.NameSecondVM(newValue);
}, this, "secondVMTakeThis");
}
</script>
var viewModelA = new MainViewModel();
var viewModelB = new SecondViewModel();
ko.applyBindings(viewModelA, document.getElementById("one"));
ko.applyBindings(viewModelB, document.getElementById("two"));

data bind weather id value to i class in mvc razor view using KO

Just trying to implement a weather forecast in my MVC5 App View using KO.
To be able to display the weather icon I have to fetch the id from the observable weather array, which I am able to obtain as follows:
<span data-bind="text:weather()[0].id"></span>
Then I have to put the id value of a particular city eg "801" in the i class like below:
<i class="wi wi-owm-ID value here+ "></i>
to display as
<i class="wi wi-owm-801"></i>
I am using the weather class
public Object getWeatherForcast()
{
string appid = "xxxxxxxxxxx";
string url = "http://api.openweathermap.org/data/2.5/weather?q=Auckland&APPID=" + appid + "&units=metric";
var client = new WebClient();
var content = client.DownloadString(url);
var serializer = new JavaScriptSerializer();
var jsonContent = serializer.Deserialize<Object>(content);
return jsonContent;
}
Everything works I am just struggling to display the weather Id in the so that an icon could be picked from the css file. Any help will be appreciated
You can make class observable with Knockout, like this:
<i data-bind="attr: {class: 'wi wi-owm-'+weather()[0].id()}"></i>
or
<i data-bind="css: 'wi wi-owm-'+weather()[0].id()"></i>
Check fiddle: Fiddle
You can calculate css class in the model and pass it to the markup via "css" binding:
function model() {
var result = {
id: 15,
style: undefined
};
result.style = ko.computed(function() {
return "some-prefix-" + result.id;
});
return result;
};
ko.applyBindings(new model());
.some-prefix-15 {
width: 30px;
height: 15px;
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="css: style"></div>

Resources