Can I transform AnyPublisher to Published.Publisher? - combine

So I have a value of type AnyPublisher<Foo, Error> and I need to transform it to Published<Foo>.Publisher so that I can use it as #Published
so the idea is that I have a MVVM architecture
struct SwiftUIView: View {
#ObservedObject var viewModel: MyViewModel
var body: some View {
Text(/*Foo has a title, how do I access it? */)
}
}
class MyViewModel: ObservableObject {
var cellModels: AnyPublisher<Foo, Error>
// so the idea is to have and then access it in swiftUI view via viewModel.cellModels2.title
#Published cellModels2 = convert_somehow_to_publisher(cellModels)
}
Apparently I cannot use viewModel.cellModels
Is that possible?

Looks like what you need is to have a Foo property on your view model, and update it using the AnyPublisher<Foo, Error> publisher that you have.
class MyViewModel: ObservableObject {
var cellModels: AnyPublisher<Foo, Error> = ...
private var cancellable: AnyCancellable?
#Published var foo: Foo?
init() {
cancellable = cellModels.assign(to: \.foo, on: self)
}
}
Then you can access .foo in the view normally:
struct SwiftUIView: View {
#ObservedObject var viewModel: MyViewModel
var body: some View {
Text(viewModel.foo?.title ?? "")
}
}

Related

Pass #Published where #Binding is required (SwiftUI, Combine)

A ViewModel class has a sourceProperty that is being edited by the TextField. That property is #Published. I'd like to pass it to the Logic class which has an initializer with Binding<String>. That class will be listening to the sourceProperty changes, react on them and set it's output to the #Published output property.
How can I pass #Published sourceProperty as an initializer parameter to the Logic class?
Relevant code:
final class ViewModel {
#Published var sourceProperty: String = ""
private var logic: Logic?
init() {
self.logic = Logic(data: $sourceProperty)
$logic.output.sink({result in
print("got result: \(result)")
})
}
}
final class Logic: ObservableObject {
private var bag = Set<AnyCancellable>()
#Published var output: String = ""
#Binding var data: String
init(data: Binding<String>) {
self._data = data
$data.sink({ newValue in
output = newvalue + "ABCDE"
}).store(in: &bag)
}
}
So far I'm getting the following error:
Cannot convert value of type 'Published.Publisher' to expected
argument type 'Binding'
The goal is to use a change in the object's own property to trigger a method invocation in another object and then bind that second object's output to some view.
View Layer:
public struct ViewLayer: View {
#Binding private var sourceProperty: String
public init(_ placeholder: String,
sourceProperty: Binding<String>,
) {
self.placeholder = placeholder
self._sourceProperty = sourceProperty
}
public var body: some View {
TextField(placeholder, text: $sourceProperty)
}
}
If I understand your question correctly, you are probably looking for something like that:
final class ViewModel: ObservableObject {
#Published var sourceProperty: String = ""
private lazy var logic = Logic(data: $sourceProperty)
private var cancellable: AnyCancellable?
init() {
cancellable = logic.$output
.sink { result in
print("got result: \(result)")
}
}
}
final class Logic: ObservableObject {
#Published private(set) var output: String = ""
init(data: Published<String>.Publisher) {
data
.map { $0 + "ABCDE" }
.assign(to: &$output)
}
}

how to send file along with data in formdata in angular 10

i want to send data in FormData along side with Files in the same object.
i have an object
var dataForm : FormData = new FormData();
var objectToSend : any = {};
objectToSend.object1 = {
Name:'Name',
ID: 1
};
objectToSend.Arr = [1,2,3];
i 've found out how to put a file in the FromData
this.dataForm.append('file', <File>files[0], (<File>files[0]).name);
but when putting the data object in it the same way i put the file like this ...
var stringfiedObejct = JSON.stringify(objectToSend);
this.dataForm.append('data', new Blob([stringfiedObejct], { type: 'application/json' }));
and the call like
this.Http.post(`apiPath`, this.dataForm, { reportProgress: true, observe: 'events' })
.subscribe(event => {
});
it generate error 415 Unsupported Media although the api method has the same definition for the object
public class DataObject
{
public int ID {get;set;}
public string Name {get;set;}
}
public class RequestParams
{
public List<int> Arr {get;set;}
public DataObject object1 {get;set;}
}
and the api is ...
[HttpPost("uploadFile"), DisableRequestSizeLimit]
public IActionResult Upload(RequestParams param)
{
var file = Request.Form.Files[0];
return Ok();
}
although the file is received in the api, but as soon i put the object in the FormData it generate that error
If you want to pass object in formdata,you can do like this:
DemoModel:
public class DemoModel
{
public IList<IFormFile> Images{ get; set; }
public DataObject object1 {get;set;}
}
pass object to FormData:
var pdata = new FormData();
pdata.append('object1.Name', 'Name');
pdata.append('object1.ID', 1);

How to implement class in TypeScript?

Could you help me to create class 'MyClass'
class M should be Newable and implement IMyInterface
export interface IMyInterface<A>
{
SomeData : A;
}
export class MyClass<T,M inherits IMyInterface<T> and new() >
{
list = new Array<M>();
privete Creator()
{
const obj = new M();
obj.SameData = 'Hello data';
list.push( obj );
}
}
Think you're looking for something like this...
export interface IMyInterface<A> {
SomeData: A;
}
export class MyClass<T, M extends IMyInterface<T>> {
private list: M[] = [];
constructor(private constructorFunction: {new(): M; }) {
}
public add(item: T): void {
const obj = new this.constructorFunction();
obj.SomeData = item;
this.list.push(obj);
}
}
export class MyItem implements IMyInterface<string> {
public SomeData: string = '';
}
const collection = new MyClass<string, MyItem>(MyItem);
collection.add('Hello data');
I've tweaked your psuedocode so that it actually compiles and does what I think you were aiming for in the question. The important thing to note is that the types in TypeScript have no representation at runtime so you can't do new T(). Instead you need to pass in the constructor function for your class which has a type of { new(): M; }. You can then do a new X() with this value to get an object which extends your interface.

How to best pass and consume JSON data from angularJs to asp.net MVC - currently always has values set to null

This is similar to: another stack overflow q
I have tried something similar to this question:
var MyItem= { "msg": "hello word!" };
$http.post("/MyController/testPost", MyItem).success(function (data) {
Alert(ok)
})
I have also tried creating MyItem as a Javascript object.
Then in MyController:
[post]
public void testPost(MyItem MyItem)
{
}
Where MyItem, looks like this:
public class MyItem
{
public string msg;
}
The action in the controller is always hit in all scenarios, but MyItem is always has a null value for msg. Am I missing something? Is there a better way of doing this?
For me it started to work when I had changed the "msg" field to property. No additional attributes except [HttpPost] for the controller.
public class MyItem
{
public string msg { get; set; }
}
[HttpPost]
public ActionResult testPost(MyItem MyItem)
{
}
I would try two options...
Try changing var MyItem= { "msg": "hello word!" }; to..
var MyItem = { msg: "hello word!" };
or
var MyItem = {};
MyItem.msg = "hello world!";

Global Object in ActionScript

private var _product:Product;
[Bindable]
public function get product():Product
{
return _product;
}
public function set product(p:Product):void
{
_product = p;
tn.selectedIndex = 0;
}
<mx:Label text="{product.name}" fontSize="11" fontWeight="bold"/>
How are they getting the product.name value which is inside product class.
package samples.flexstore
{
[Bindable]
public class Product
{
public var productId:int;
public var name:String;
public var description:String;
public var price:Number;
public var image:String;
public var series:String;
public var triband:Boolean;
public var camera:Boolean;
public var video:Boolean;
public var highlight1:String;
public var highlight2:String;
public var qty:int;
public function Product()
{
}
public function fill(obj:Object):void
{
for (var i:String in obj)
{
this[i] = obj[i];
}
}
[Bindable(event="propertyChange")]
public function get featureString():String
{
var str:String = "";
if (triband)
str += "Tri-band ";
if (camera)
str += "Camera ";
if (video)
str += "Video";
return str;
}
}
}
"{product.name}" , the product refers to the getter method!
That's the trick of Flex/ActionScript 3's getter and setter methods
http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=ascomponents_147_08.html
"name" is a public var on the Product class. By definition, "name" will be accessible to any other class. That's what "public" means.
_product is a private instance of the Product class. They are supplying the set product method with a Product value, which sets the _product private variable to an instance of the Product class.
The bracket notation in the text="{product.name}" portion of the above code is shorthand notation for binding the contained variable, in this case the name property of the product instance, to the component property (text). When the set product method is supplied a Product instance, Flex fires events internally that update the components that have that property bound.
Defining Data Models - Flex Quickstarts

Resources